commit
ea5850cf93
30
CHANGELOG.md
30
CHANGELOG.md
@ -9,6 +9,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Changed
|
### Changed
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
|
## [4.3.0]
|
||||||
|
### Added
|
||||||
|
- Added documentation (moved from `protocol`)
|
||||||
|
- `Frac.aes` – library for rational numbers
|
||||||
|
- Added some more meaningful error messages
|
||||||
|
- Exported several parsing functionalities
|
||||||
|
- With option `keep_included` it is possible to see which files were included during the parse
|
||||||
|
- There is a function `run_parser` that be used to evaluate any parsing rule
|
||||||
|
- Exported parsers: `body`, `type` and `decl`
|
||||||
|
### Changed
|
||||||
|
- Performance improvements in the standard library
|
||||||
|
- Fixed ACI encoder to handle `-` unary operator
|
||||||
|
- Fixed including by absolute path
|
||||||
|
- Fixed variant type printing in the ACI error messages
|
||||||
|
- Fixed pretty printing of combined function clauses
|
||||||
|
### Removed
|
||||||
|
- `let` definitions are no longer supported in the toplevel of the contract
|
||||||
|
- type declarations are no longer supported
|
||||||
|
|
||||||
## [4.2.0] - 2020-01-15
|
## [4.2.0] - 2020-01-15
|
||||||
### Added
|
### Added
|
||||||
- Allow separate entrypoint/function type signature and definition, and pattern
|
- Allow separate entrypoint/function type signature and definition, and pattern
|
||||||
@ -53,7 +72,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
(de-)construct byte arrays.
|
(de-)construct byte arrays.
|
||||||
- `[a..b]` language construct, returning the list of numbers between
|
- `[a..b]` language construct, returning the list of numbers between
|
||||||
`a` and `b` (inclusive). Returns the empty list if `a` > `b`.
|
`a` and `b` (inclusive). Returns the empty list if `a` > `b`.
|
||||||
- [Standard libraries] (https://github.com/aeternity/protocol/blob/master/contracts/sophia_stdlib.md)
|
- [Standard libraries](https://github.com/aeternity/aesophia/blob/master/docs/sophia_stdlib.md)
|
||||||
- Checks that `init` is not called from other functions.
|
- Checks that `init` is not called from other functions.
|
||||||
- FATE backend - the compiler is able to produce VM code for both `AEVM` and `FATE`. Many
|
- FATE backend - the compiler is able to produce VM code for both `AEVM` and `FATE`. Many
|
||||||
of the APIs now take `{backend, aevm | fate}` to decide wich backend to produce artifacts
|
of the APIs now take `{backend, aevm | fate}` to decide wich backend to produce artifacts
|
||||||
@ -192,10 +211,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Simplify calldata creation - instead of passing a compiled contract, simply
|
- Simplify calldata creation - instead of passing a compiled contract, simply
|
||||||
pass a (stubbed) contract string.
|
pass a (stubbed) contract string.
|
||||||
|
|
||||||
[Unreleased]: https://github.com/aeternity/aesophia/compare/v4.2.0...HEAD
|
[Unreleased]: https://github.com/aeternity/aesophia/compare/v4.3.0...HEAD
|
||||||
[4.2.0]: https://github.com/aeternity/aesophia/compare/v4.2.0...v4.1.0
|
[4.3.0]: https://github.com/aeternity/aesophia/compare/v4.2.0...v4.3.0
|
||||||
[4.1.0]: https://github.com/aeternity/aesophia/compare/v4.1.0...v4.0.0
|
[4.2.0]: https://github.com/aeternity/aesophia/compare/v4.1.0...v4.2.0
|
||||||
[4.0.0]: https://github.com/aeternity/aesophia/compare/v4.0.0...v3.2.0
|
[4.1.0]: https://github.com/aeternity/aesophia/compare/v4.0.0...v4.1.0
|
||||||
|
[4.0.0]: https://github.com/aeternity/aesophia/compare/v3.2.0...v4.0.0
|
||||||
[3.2.0]: https://github.com/aeternity/aesophia/compare/v3.1.0...v3.2.0
|
[3.2.0]: https://github.com/aeternity/aesophia/compare/v3.1.0...v3.2.0
|
||||||
[3.1.0]: https://github.com/aeternity/aesophia/compare/v3.0.0...v3.1.0
|
[3.1.0]: https://github.com/aeternity/aesophia/compare/v3.0.0...v3.1.0
|
||||||
[3.0.0]: https://github.com/aeternity/aesophia/compare/v2.1.0...v3.0.0
|
[3.0.0]: https://github.com/aeternity/aesophia/compare/v2.1.0...v3.0.0
|
||||||
|
11
README.md
11
README.md
@ -2,13 +2,19 @@
|
|||||||
|
|
||||||
This is the __sophia__ compiler for the æternity system which compiles contracts written in __sophia__ code to the æternity VM code.
|
This is the __sophia__ compiler for the æternity system which compiles contracts written in __sophia__ code to the æternity VM code.
|
||||||
|
|
||||||
For more information about æternity smart contracts and the sophia language see [Smart Contracts](https://github.com/aeternity/protocol/blob/master/contracts/contracts.md) and the [Sophia Language](https://github.com/aeternity/protocol/blob/master/contracts/sophia.md).
|
|
||||||
|
|
||||||
It is an OTP application written in Erlang and is by default included in
|
It is an OTP application written in Erlang and is by default included in
|
||||||
[the æternity node](https://github.com/aeternity/epoch). However, it can
|
[the æternity node](https://github.com/aeternity/epoch). However, it can
|
||||||
also be included in other systems to compile contracts coded in sophia which
|
also be included in other systems to compile contracts coded in sophia which
|
||||||
can then be loaded into the æternity system.
|
can then be loaded into the æternity system.
|
||||||
|
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
* [Smart Contracts on aeternity Blockchain](https://github.com/aeternity/protocol/blob/master/contracts/contracts.md).
|
||||||
|
* [Sophia Documentation](docs/sophia.md).
|
||||||
|
* [Sophia Standard Library](docs/sophia_stdlib.md).
|
||||||
|
|
||||||
|
|
||||||
## Versioning
|
## Versioning
|
||||||
|
|
||||||
`aesophia` has a version that is only loosely connected to the version of the
|
`aesophia` has a version that is only loosely connected to the version of the
|
||||||
@ -17,6 +23,7 @@ minor/patch version. The `aesophia` compiler version MUST be bumped whenever
|
|||||||
there is a change in how byte code is generated, but it MAY also be bumped upon
|
there is a change in how byte code is generated, but it MAY also be bumped upon
|
||||||
API changes etc.
|
API changes etc.
|
||||||
|
|
||||||
|
|
||||||
## Interface Modules
|
## Interface Modules
|
||||||
|
|
||||||
The basic modules for interfacing the compiler:
|
The basic modules for interfacing the compiler:
|
||||||
|
1159
docs/sophia.md
Normal file
1159
docs/sophia.md
Normal file
File diff suppressed because it is too large
Load Diff
2071
docs/sophia_stdlib.md
Normal file
2071
docs/sophia_stdlib.md
Normal file
File diff suppressed because it is too large
Load Diff
183
priv/stdlib/Frac.aes
Normal file
183
priv/stdlib/Frac.aes
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
namespace Frac =
|
||||||
|
|
||||||
|
private function gcd(a : int, b : int) =
|
||||||
|
if (b == 0) a else gcd(b, a mod b)
|
||||||
|
|
||||||
|
private function abs_int(a : int) = if (a < 0) -a else a
|
||||||
|
|
||||||
|
datatype frac = Pos(int, int) | Zero | Neg(int, int)
|
||||||
|
|
||||||
|
/** Checks if the internal representation is correct.
|
||||||
|
* Numerator and denominator must be positive.
|
||||||
|
* Exposed for debug purposes
|
||||||
|
*/
|
||||||
|
function is_sane(f : frac) : bool = switch(f)
|
||||||
|
Pos(n, d) => n > 0 && d > 0
|
||||||
|
Zero => true
|
||||||
|
Neg(n, d) => n > 0 && d > 0
|
||||||
|
|
||||||
|
function num(f : frac) : int = switch(f)
|
||||||
|
Pos(n, _) => n
|
||||||
|
Neg(n, _) => -n
|
||||||
|
Zero => 0
|
||||||
|
|
||||||
|
function den(f : frac) : int = switch(f)
|
||||||
|
Pos(_, d) => d
|
||||||
|
Neg(_, d) => d
|
||||||
|
Zero => 1
|
||||||
|
|
||||||
|
function to_pair(f : frac) : int * int = switch(f)
|
||||||
|
Pos(n, d) => (n, d)
|
||||||
|
Neg(n, d) => (-n, d)
|
||||||
|
Zero => (0, 1)
|
||||||
|
|
||||||
|
function sign(f : frac) : int = switch(f)
|
||||||
|
Pos(_, _) => 1
|
||||||
|
Neg(_, _) => -1
|
||||||
|
Zero => 0
|
||||||
|
|
||||||
|
function to_str(f : frac) : string = switch(f)
|
||||||
|
Pos(n, d) => String.concat(Int.to_str(n), if (d == 1) "" else String.concat("/", Int.to_str(d)))
|
||||||
|
Neg(n, d) => String.concat("-", to_str(Pos(n, d)))
|
||||||
|
Zero => "0"
|
||||||
|
|
||||||
|
/** Reduce fraction to normal form
|
||||||
|
*/
|
||||||
|
function simplify(f : frac) : frac =
|
||||||
|
switch(f)
|
||||||
|
Neg(n, d) =>
|
||||||
|
let cd = gcd(n, d)
|
||||||
|
Neg(n / cd, d / cd)
|
||||||
|
Zero => Zero
|
||||||
|
Pos(n, d) =>
|
||||||
|
let cd = gcd(n, d)
|
||||||
|
Pos(n / cd, d / cd)
|
||||||
|
|
||||||
|
/** Integer to rational division
|
||||||
|
*/
|
||||||
|
function make_frac(n : int, d : int) : frac =
|
||||||
|
if (d == 0) abort("Zero denominator")
|
||||||
|
elif (n == 0) Zero
|
||||||
|
elif ((n < 0) == (d < 0)) simplify(Pos(abs_int(n), abs_int(d)))
|
||||||
|
else simplify(Neg(abs_int(n), abs_int(d)))
|
||||||
|
|
||||||
|
function one() : frac = Pos(1, 1)
|
||||||
|
function zero() : frac = Zero
|
||||||
|
|
||||||
|
function eq(a : frac, b : frac) : bool =
|
||||||
|
let (na, da) = to_pair(a)
|
||||||
|
let (nb, db) = to_pair(b)
|
||||||
|
(na == nb && da == db) || na * db == nb * da // they are more likely to be normalized
|
||||||
|
|
||||||
|
function neq(a : frac, b : frac) : bool =
|
||||||
|
let (na, da) = to_pair(a)
|
||||||
|
let (nb, db) = to_pair(b)
|
||||||
|
(na != nb || da != db) && na * db != nb * da
|
||||||
|
|
||||||
|
function geq(a : frac, b : frac) : bool = num(a) * den(b) >= num(b) * den(a)
|
||||||
|
|
||||||
|
function leq(a : frac, b : frac) : bool = num(a) * den(b) =< num(b) * den(a)
|
||||||
|
|
||||||
|
function gt(a : frac, b : frac) : bool = num(a) * den(b) > num(b) * den(a)
|
||||||
|
|
||||||
|
function lt(a : frac, b : frac) : bool = num(a) * den(b) < num(b) * den(a)
|
||||||
|
|
||||||
|
function min(a : frac, b : frac) : frac = if (leq(a, b)) a else b
|
||||||
|
|
||||||
|
function max(a : frac, b : frac) : frac = if (geq(a, b)) a else b
|
||||||
|
|
||||||
|
function abs(f : frac) : frac = switch(f)
|
||||||
|
Pos(n, d) => Pos(n, d)
|
||||||
|
Zero => Zero
|
||||||
|
Neg(n, d) => Pos(n, d)
|
||||||
|
|
||||||
|
function from_int(n : int) : frac =
|
||||||
|
if (n > 0) Pos(n, 1)
|
||||||
|
elif (n < 0) Neg(-n, 1)
|
||||||
|
else Zero
|
||||||
|
|
||||||
|
function floor(f : frac) : int = switch(f)
|
||||||
|
Pos(n, d) => n / d
|
||||||
|
Zero => 0
|
||||||
|
Neg(n, d) => -(n + d - 1) / d
|
||||||
|
|
||||||
|
function ceil(f : frac) : int = switch(f)
|
||||||
|
Pos(n, d) => (n + d - 1) / d
|
||||||
|
Zero => 0
|
||||||
|
Neg(n, d) => -n / d
|
||||||
|
|
||||||
|
function round_to_zero(f : frac) : int = switch(f)
|
||||||
|
Pos(n, d) => n / d
|
||||||
|
Zero => 0
|
||||||
|
Neg(n, d) => -n / d
|
||||||
|
|
||||||
|
function round_from_zero(f : frac) : int = switch(f)
|
||||||
|
Pos(n, d) => (n + d - 1) / d
|
||||||
|
Zero => 0
|
||||||
|
Neg(n, d) => -(n + d - 1) / d
|
||||||
|
|
||||||
|
/** Round towards nearest integer. If two integers are in the same
|
||||||
|
* distance, choose the even one.
|
||||||
|
*/
|
||||||
|
function round(f : frac) : int =
|
||||||
|
let fl = floor(f)
|
||||||
|
let cl = ceil(f)
|
||||||
|
let dif_fl = abs(sub(f, from_int(fl)))
|
||||||
|
let dif_cl = abs(sub(f, from_int(cl)))
|
||||||
|
if (gt(dif_fl, dif_cl)) cl
|
||||||
|
elif (gt(dif_cl, dif_fl)) fl
|
||||||
|
elif (fl mod 2 == 0) fl
|
||||||
|
else cl
|
||||||
|
|
||||||
|
function add(a : frac, b : frac) : frac =
|
||||||
|
let (na, da) = to_pair(a)
|
||||||
|
let (nb, db) = to_pair(b)
|
||||||
|
if (da == db) make_frac(na + nb, da)
|
||||||
|
else make_frac(na * db + nb * da, da * db)
|
||||||
|
|
||||||
|
function neg(a : frac) : frac = switch(a)
|
||||||
|
Neg(n, d) => Pos(n, d)
|
||||||
|
Zero => Zero
|
||||||
|
Pos(n, d) => Neg(n, d)
|
||||||
|
|
||||||
|
function sub(a : frac, b : frac) : frac = add(a, neg(b))
|
||||||
|
|
||||||
|
function inv(a : frac) : frac = switch(a)
|
||||||
|
Neg(n, d) => Neg(d, n)
|
||||||
|
Zero => abort("Inversion of zero")
|
||||||
|
Pos(n, d) => Pos(d, n)
|
||||||
|
|
||||||
|
function mul(a : frac, b : frac) : frac = make_frac(num(a) * num(b), den(a) * den(b))
|
||||||
|
|
||||||
|
function div(a : frac, b : frac) : frac = switch(b)
|
||||||
|
Neg(n, d) => mul(a, Neg(d, n))
|
||||||
|
Zero => abort("Division by zero")
|
||||||
|
Pos(n, d) => mul(a, Pos(d, n))
|
||||||
|
|
||||||
|
/** `b` to the power of `e`
|
||||||
|
*/
|
||||||
|
function int_exp(b : frac, e : int) : frac =
|
||||||
|
if (sign(b) == 0 && e == 0) abort("Zero to the zero exponentation")
|
||||||
|
elif (e < 0) inv(int_exp_(b, -e))
|
||||||
|
else int_exp_(b, e)
|
||||||
|
private function int_exp_(b : frac, e : int) =
|
||||||
|
if (e == 0) from_int(1)
|
||||||
|
elif (e == 1) b
|
||||||
|
else
|
||||||
|
let half = int_exp_(b, e / 2)
|
||||||
|
if (e mod 2 == 1) mul(mul(half, half), b)
|
||||||
|
else mul(half, half)
|
||||||
|
|
||||||
|
/** Reduces the fraction's in-memory size by dividing its components by two until the
|
||||||
|
* the error is bigger than `loss` value
|
||||||
|
*/
|
||||||
|
function optimize(f : frac, loss : frac) : frac =
|
||||||
|
require(geq(loss, Zero), "negative loss optimize")
|
||||||
|
let s = sign(f)
|
||||||
|
mul(from_int(s), run_optimize(abs(f), abs(f), loss))
|
||||||
|
private function run_optimize(orig : frac, f : frac, loss : frac) : frac =
|
||||||
|
let (n, d) = to_pair(f)
|
||||||
|
let t = make_frac((n+1)/2, (d+1)/2)
|
||||||
|
if(gt(abs(sub(t, orig)), loss)) f
|
||||||
|
elif (eq(t, f)) f
|
||||||
|
else run_optimize(orig, t, loss)
|
@ -12,35 +12,66 @@ namespace Func =
|
|||||||
|
|
||||||
function rapply(x : 'a, f : 'a => 'b) : 'b = f(x)
|
function rapply(x : 'a, f : 'a => 'b) : 'b = f(x)
|
||||||
|
|
||||||
/* The Z combinator - replacement for local and anonymous recursion.
|
/** The Z combinator - replacement for local and anonymous recursion.
|
||||||
*/
|
*/
|
||||||
function recur(f : ('arg => 'res, 'arg) => 'res) : 'arg => 'res =
|
function recur(f : ('arg => 'res, 'arg) => 'res) : 'arg => 'res =
|
||||||
(x) => f(recur(f), x)
|
(x) => f(recur(f), x)
|
||||||
|
|
||||||
|
/** n-times composition with itself
|
||||||
|
*/
|
||||||
function iter(n : int, f : 'a => 'a) : 'a => 'a = iter_(n, f, (x) => x)
|
function iter(n : int, f : 'a => 'a) : 'a => 'a = iter_(n, f, (x) => x)
|
||||||
private function iter_(n : int, f : 'a => 'a, acc : 'a => 'a) : 'a => 'a =
|
private function iter_(n : int, f : 'a => 'a, acc : 'a => 'a) : 'a => 'a =
|
||||||
if(n == 0) acc
|
if(n == 0) acc
|
||||||
elif(n == 1) comp(f, acc)
|
elif(n == 1) comp(f, acc)
|
||||||
else iter_(n / 2, comp(f, f), if(n mod 2 == 0) acc else comp(f, acc))
|
else iter_(n / 2, comp(f, f), if(n mod 2 == 0) acc else comp(f, acc))
|
||||||
|
|
||||||
function curry2(f : ('a, 'b) => 'c) : 'a => ('b => 'c) =
|
/** Turns an ugly, bad and disgusting arity-n function into
|
||||||
|
* a beautiful and sweet function taking the first argument
|
||||||
|
* and returning a function watiting for the remaining ones
|
||||||
|
* in the same manner
|
||||||
|
*/
|
||||||
|
function curry2(f : ('a, 'b) => 'x) : 'a => ('b => 'x) =
|
||||||
(x) => (y) => f(x, y)
|
(x) => (y) => f(x, y)
|
||||||
function curry3(f : ('a, 'b, 'c) => 'd) : 'a => ('b => ('c => 'd)) =
|
function curry3(f : ('a, 'b, 'c) => 'x) : 'a => ('b => ('c => 'x)) =
|
||||||
(x) => (y) => (z) => f(x, y, z)
|
(x) => (y) => (z) => f(x, y, z)
|
||||||
|
function curry4(f : ('a, 'b, 'c, 'd) => 'x) : 'a => ('b => ('c => ('d => 'x))) =
|
||||||
|
(x) => (y) => (z) => (w) => f(x, y, z, w)
|
||||||
|
function curry5(f : ('a, 'b, 'c, 'd, 'e) => 'x) : 'a => ('b => ('c => ('d => ('e => 'x)))) =
|
||||||
|
(x) => (y) => (z) => (w) => (q) => f(x, y, z, w, q)
|
||||||
|
|
||||||
function uncurry2(f : 'a => ('b => 'c)) : ('a, 'b) => 'c =
|
/** Opposite of curry. Gross
|
||||||
|
*/
|
||||||
|
function uncurry2(f : 'a => ('b => 'x)) : ('a, 'b) => 'x =
|
||||||
(x, y) => f(x)(y)
|
(x, y) => f(x)(y)
|
||||||
function uncurry3(f : 'a => ('b => ('c => 'd))) : ('a, 'b, 'c) => 'd =
|
function uncurry3(f : 'a => ('b => ('c => 'x))) : ('a, 'b, 'c) => 'x =
|
||||||
(x, y, z) => f(x)(y)(z)
|
(x, y, z) => f(x)(y)(z)
|
||||||
|
function uncurry4(f : 'a => ('b => ('c => ('d => 'x)))) : ('a, 'b, 'c, 'd) => 'x =
|
||||||
|
(x, y, z, w) => f(x)(y)(z)(w)
|
||||||
|
function uncurry5(f : 'a => ('b => ('c => ('d => ('e => 'x))))) : ('a, 'b, 'c, 'd, 'e) => 'x =
|
||||||
|
(x, y, z, w, q) => f(x)(y)(z)(w)(q)
|
||||||
|
|
||||||
function tuplify2(f : ('a, 'b) => 'c) : (('a * 'b)) => 'c =
|
/** Turns an arity-n function into a function taking n-tuple
|
||||||
|
*/
|
||||||
|
function tuplify2(f : ('a, 'b) => 'x) : (('a * 'b)) => 'x =
|
||||||
(t) => switch(t)
|
(t) => switch(t)
|
||||||
(x, y) => f(x, y)
|
(x, y) => f(x, y)
|
||||||
function tuplify3(f : ('a, 'b, 'c) => 'd) : 'a * 'b * 'c => 'd =
|
function tuplify3(f : ('a, 'b, 'c) => 'x) : 'a * 'b * 'c => 'x =
|
||||||
(t) => switch(t)
|
(t) => switch(t)
|
||||||
(x, y, z) => f(x, y, z)
|
(x, y, z) => f(x, y, z)
|
||||||
|
function tuplify4(f : ('a, 'b, 'c, 'd) => 'x) : 'a * 'b * 'c * 'd => 'x =
|
||||||
|
(t) => switch(t)
|
||||||
|
(x, y, z, w) => f(x, y, z, w)
|
||||||
|
function tuplify5(f : ('a, 'b, 'c, 'd, 'e) => 'x) : 'a * 'b * 'c * 'd * 'e => 'x =
|
||||||
|
(t) => switch(t)
|
||||||
|
(x, y, z, w, q) => f(x, y, z, w, q)
|
||||||
|
|
||||||
function untuplify2(f : 'a * 'b => 'c) : ('a, 'b) => 'c =
|
/** Opposite of tuplify
|
||||||
|
*/
|
||||||
|
function untuplify2(f : 'a * 'b => 'x) : ('a, 'b) => 'x =
|
||||||
(x, y) => f((x, y))
|
(x, y) => f((x, y))
|
||||||
function untuplify3(f : 'a * 'b * 'c => 'd) : ('a, 'b, 'c) => 'd =
|
function untuplify3(f : 'a * 'b * 'c => 'x) : ('a, 'b, 'c) => 'x =
|
||||||
(x, y, z) => f((x, y, z))
|
(x, y, z) => f((x, y, z))
|
||||||
|
function untuplify4(f : 'a * 'b * 'c * 'd => 'x) : ('a, 'b, 'c, 'd) => 'x =
|
||||||
|
(x, y, z, w) => f((x, y, z, w))
|
||||||
|
function untuplify5(f : 'a * 'b * 'c * 'd * 'e => 'x) : ('a, 'b, 'c, 'd, 'e) => 'x =
|
||||||
|
(x, y, z, w, q) => f((x, y, z, w, q))
|
||||||
|
@ -28,10 +28,15 @@ namespace List =
|
|||||||
h::t => h::drop_last_unsafe(t)
|
h::t => h::drop_last_unsafe(t)
|
||||||
[] => abort("drop_last_unsafe: list empty")
|
[] => abort("drop_last_unsafe: list empty")
|
||||||
|
|
||||||
|
/** Finds first element of `l` fulfilling predicate `p` as `Some` or `None`
|
||||||
|
* if no such element exists.
|
||||||
|
*/
|
||||||
function find(p : 'a => bool, l : list('a)) : option('a) = switch(l)
|
function find(p : 'a => bool, l : list('a)) : option('a) = switch(l)
|
||||||
[] => None
|
[] => None
|
||||||
h::t => if(p(h)) Some(h) else find(p, t)
|
h::t => if(p(h)) Some(h) else find(p, t)
|
||||||
|
|
||||||
|
/** Returns list of all indices of elements from `l` that fulfill the predicate `p`.
|
||||||
|
*/
|
||||||
function find_indices(p : 'a => bool, l : list('a)) : list(int) = find_indices_(p, l, 0)
|
function find_indices(p : 'a => bool, l : list('a)) : list(int) = find_indices_(p, l, 0)
|
||||||
private function find_indices_( p : 'a => bool
|
private function find_indices_( p : 'a => bool
|
||||||
, l : list('a)
|
, l : list('a)
|
||||||
@ -60,8 +65,15 @@ namespace List =
|
|||||||
_::t => length_(t, acc + 1)
|
_::t => length_(t, acc + 1)
|
||||||
|
|
||||||
|
|
||||||
|
/** Creates an ascending sequence of all integer numbers
|
||||||
|
* between `a` and `b` (including `a` and `b`)
|
||||||
|
*/
|
||||||
function from_to(a : int, b : int) : list(int) = [a..b]
|
function from_to(a : int, b : int) : list(int) = [a..b]
|
||||||
|
|
||||||
|
/** Creates an ascending sequence of integer numbers betweeen
|
||||||
|
* `a` and `b` jumping by given `step`. Includes `a` and takes
|
||||||
|
* `b` only if `(b - a) mod step == 0`. `step` should be bigger than 0.
|
||||||
|
*/
|
||||||
function from_to_step(a : int, b : int, s : int) : list(int) =
|
function from_to_step(a : int, b : int, s : int) : list(int) =
|
||||||
from_to_step_(a, b - (b-a) mod s, s, [])
|
from_to_step_(a, b - (b-a) mod s, s, [])
|
||||||
private function from_to_step_(a : int, b : int, s : int, acc : list(int)) : list(int) =
|
private function from_to_step_(a : int, b : int, s : int, acc : list(int)) : list(int) =
|
||||||
@ -69,8 +81,8 @@ namespace List =
|
|||||||
else from_to_step_(a, b - s, s, b::acc)
|
else from_to_step_(a, b - s, s, b::acc)
|
||||||
|
|
||||||
|
|
||||||
|
/** Unsafe. Replaces `n`th element of `l` with `e`. Crashes on over/underflow
|
||||||
/* Unsafe. Replaces `n`th element of `l` with `e`. Crashes on over/underflow */
|
*/
|
||||||
function replace_at(n : int, e : 'a, l : list('a)) : list('a) =
|
function replace_at(n : int, e : 'a, l : list('a)) : list('a) =
|
||||||
if(n<0) abort("insert_at underflow") else replace_at_(n, e, l)
|
if(n<0) abort("insert_at underflow") else replace_at_(n, e, l)
|
||||||
private function replace_at_(n : int, e : 'a, l : list('a)) : list('a) =
|
private function replace_at_(n : int, e : 'a, l : list('a)) : list('a) =
|
||||||
@ -79,7 +91,8 @@ namespace List =
|
|||||||
h::t => if (n == 0) e::t
|
h::t => if (n == 0) e::t
|
||||||
else h::replace_at_(n-1, e, t)
|
else h::replace_at_(n-1, e, t)
|
||||||
|
|
||||||
/* Unsafe. Adds `e` to `l` to be its `n`th element. Crashes on over/underflow */
|
/** Unsafe. Adds `e` to `l` to be its `n`th element. Crashes on over/underflow
|
||||||
|
*/
|
||||||
function insert_at(n : int, e : 'a, l : list('a)) : list('a) =
|
function insert_at(n : int, e : 'a, l : list('a)) : list('a) =
|
||||||
if(n<0) abort("insert_at underflow") else insert_at_(n, e, l)
|
if(n<0) abort("insert_at underflow") else insert_at_(n, e, l)
|
||||||
private function insert_at_(n : int, e : 'a, l : list('a)) : list('a) =
|
private function insert_at_(n : int, e : 'a, l : list('a)) : list('a) =
|
||||||
@ -88,6 +101,9 @@ namespace List =
|
|||||||
[] => abort("insert_at overflow")
|
[] => abort("insert_at overflow")
|
||||||
h::t => h::insert_at_(n-1, e, t)
|
h::t => h::insert_at_(n-1, e, t)
|
||||||
|
|
||||||
|
/** Assuming that cmp represents `<` comparison, inserts `x` before
|
||||||
|
* the first element in the list `l` which is greater than it
|
||||||
|
*/
|
||||||
function insert_by(cmp : (('a, 'a) => bool), x : 'a, l : list('a)) : list('a) =
|
function insert_by(cmp : (('a, 'a) => bool), x : 'a, l : list('a)) : list('a) =
|
||||||
switch(l)
|
switch(l)
|
||||||
[] => [x]
|
[] => [x]
|
||||||
@ -122,6 +138,8 @@ namespace List =
|
|||||||
[] => []
|
[] => []
|
||||||
h::t => f(h)::map(f, t)
|
h::t => f(h)::map(f, t)
|
||||||
|
|
||||||
|
/** Effectively composition of `map` and `flatten`
|
||||||
|
*/
|
||||||
function flat_map(f : 'a => list('b), l : list('a)) : list('b) =
|
function flat_map(f : 'a => list('b), l : list('a)) : list('b) =
|
||||||
ListInternal.flat_map(f, l)
|
ListInternal.flat_map(f, l)
|
||||||
|
|
||||||
@ -131,7 +149,8 @@ namespace List =
|
|||||||
let rest = filter(p, t)
|
let rest = filter(p, t)
|
||||||
if(p(h)) h::rest else rest
|
if(p(h)) h::rest else rest
|
||||||
|
|
||||||
/* Take up to `n` first elements */
|
/** Take up to `n` first elements
|
||||||
|
*/
|
||||||
function take(n : int, l : list('a)) : list('a) =
|
function take(n : int, l : list('a)) : list('a) =
|
||||||
if(n < 0) abort("Take negative number of elements") else take_(n, l)
|
if(n < 0) abort("Take negative number of elements") else take_(n, l)
|
||||||
private function take_(n : int, l : list('a)) : list('a) =
|
private function take_(n : int, l : list('a)) : list('a) =
|
||||||
@ -140,7 +159,8 @@ namespace List =
|
|||||||
[] => []
|
[] => []
|
||||||
h::t => h::take_(n-1, t)
|
h::t => h::take_(n-1, t)
|
||||||
|
|
||||||
/* Drop up to `n` first elements */
|
/** Drop up to `n` first elements
|
||||||
|
*/
|
||||||
function drop(n : int, l : list('a)) : list('a) =
|
function drop(n : int, l : list('a)) : list('a) =
|
||||||
if(n < 0) abort("Drop negative number of elements") else drop_(n, l)
|
if(n < 0) abort("Drop negative number of elements") else drop_(n, l)
|
||||||
private function drop_(n : int, l : list('a)) : list('a) =
|
private function drop_(n : int, l : list('a)) : list('a) =
|
||||||
@ -149,17 +169,22 @@ namespace List =
|
|||||||
[] => []
|
[] => []
|
||||||
h::t => drop_(n-1, t)
|
h::t => drop_(n-1, t)
|
||||||
|
|
||||||
/* Get the longest prefix of a list in which every element matches predicate `p` */
|
/** Get the longest prefix of a list in which every element
|
||||||
|
* matches predicate `p`
|
||||||
|
*/
|
||||||
function take_while(p : 'a => bool, l : list('a)) : list('a) = switch(l)
|
function take_while(p : 'a => bool, l : list('a)) : list('a) = switch(l)
|
||||||
[] => []
|
[] => []
|
||||||
h::t => if(p(h)) h::take_while(p, t) else []
|
h::t => if(p(h)) h::take_while(p, t) else []
|
||||||
|
|
||||||
/* Drop elements from `l` until `p` holds */
|
/** Drop elements from `l` until `p` holds
|
||||||
|
*/
|
||||||
function drop_while(p : 'a => bool, l : list('a)) : list('a) = switch(l)
|
function drop_while(p : 'a => bool, l : list('a)) : list('a) = switch(l)
|
||||||
[] => []
|
[] => []
|
||||||
h::t => if(p(h)) drop_while(p, t) else l
|
h::t => if(p(h)) drop_while(p, t) else l
|
||||||
|
|
||||||
/* Splits list into two lists of elements that respectively match and don't match predicate `p` */
|
/** Splits list into two lists of elements that respectively
|
||||||
|
* match and don't match predicate `p`
|
||||||
|
*/
|
||||||
function partition(p : 'a => bool, l : list('a)) : (list('a) * list('a)) = switch(l)
|
function partition(p : 'a => bool, l : list('a)) : (list('a) * list('a)) = switch(l)
|
||||||
[] => ([], [])
|
[] => ([], [])
|
||||||
h::t =>
|
h::t =>
|
||||||
@ -183,7 +208,9 @@ namespace List =
|
|||||||
function product(l : list(int)) : int = foldl((a, b) => a * b, 1, l)
|
function product(l : list(int)) : int = foldl((a, b) => a * b, 1, l)
|
||||||
|
|
||||||
|
|
||||||
/* Zips two list by applying bimapping function on respective elements. Drops longer tail. */
|
/** Zips two list by applying bimapping function on respective elements.
|
||||||
|
* Drops the tail of the longer list.
|
||||||
|
*/
|
||||||
private function zip_with( f : ('a, 'b) => 'c
|
private function zip_with( f : ('a, 'b) => 'c
|
||||||
, l1 : list('a)
|
, l1 : list('a)
|
||||||
, l2 : list('b)
|
, l2 : list('b)
|
||||||
@ -191,7 +218,9 @@ namespace List =
|
|||||||
(h1::t1, h2::t2) => f(h1, h2)::zip_with(f, t1, t2)
|
(h1::t1, h2::t2) => f(h1, h2)::zip_with(f, t1, t2)
|
||||||
_ => []
|
_ => []
|
||||||
|
|
||||||
/* Zips two lists into list of pairs. Drops longer tail. */
|
/** Zips two lists into list of pairs.
|
||||||
|
* Drops the tail of the longer list.
|
||||||
|
*/
|
||||||
function zip(l1 : list('a), l2 : list('b)) : list('a * 'b) = zip_with((a, b) => (a, b), l1, l2)
|
function zip(l1 : list('a), l2 : list('b)) : list('a * 'b) = zip_with((a, b) => (a, b), l1, l2)
|
||||||
|
|
||||||
function unzip(l : list('a * 'b)) : (list('a) * list('b)) = switch(l)
|
function unzip(l : list('a * 'b)) : (list('a) * list('b)) = switch(l)
|
||||||
@ -207,15 +236,16 @@ namespace List =
|
|||||||
h::t => switch (partition((x) => lesser_cmp(x, h), t))
|
h::t => switch (partition((x) => lesser_cmp(x, h), t))
|
||||||
(lesser, bigger) => sort(lesser_cmp, lesser) ++ h::sort(lesser_cmp, bigger)
|
(lesser, bigger) => sort(lesser_cmp, lesser) ++ h::sort(lesser_cmp, bigger)
|
||||||
|
|
||||||
|
/** Puts `delim` between every two members of the list
|
||||||
|
*/
|
||||||
function intersperse(delim : 'a, l : list('a)) : list('a) = switch(l)
|
function intersperse(delim : 'a, l : list('a)) : list('a) = switch(l)
|
||||||
[] => []
|
[] => []
|
||||||
[e] => [e]
|
[e] => [e]
|
||||||
h::t => h::delim::intersperse(delim, t)
|
h::t => h::delim::intersperse(delim, t)
|
||||||
|
|
||||||
|
/** Effectively a zip with an infinite sequence of natural numbers
|
||||||
|
*/
|
||||||
function enumerate(l : list('a)) : list(int * 'a) = enumerate_(l, 0)
|
function enumerate(l : list('a)) : list(int * 'a) = enumerate_(l, 0)
|
||||||
private function enumerate_(l : list('a), n : int) : list(int * 'a) = switch(l)
|
private function enumerate_(l : list('a), n : int) : list(int * 'a) = switch(l)
|
||||||
[] => []
|
[] => []
|
||||||
h::t => (n, h)::enumerate_(t, n + 1)
|
h::t => (n, h)::enumerate_(t, n + 1)
|
||||||
|
|
@ -10,13 +10,18 @@ namespace Option =
|
|||||||
None => false
|
None => false
|
||||||
Some(_) => true
|
Some(_) => true
|
||||||
|
|
||||||
|
/** Catamorphism on `option`. Also known as inlined pattern matching.
|
||||||
|
*/
|
||||||
function match(n : 'b, s : 'a => 'b, o : option('a)) : 'b = switch(o)
|
function match(n : 'b, s : 'a => 'b, o : option('a)) : 'b = switch(o)
|
||||||
None => n
|
None => n
|
||||||
Some(x) => s(x)
|
Some(x) => s(x)
|
||||||
|
|
||||||
|
/** Escape option providing default if `None`
|
||||||
|
*/
|
||||||
function default(def : 'a, o : option('a)) : 'a = match(def, (x) => x, o)
|
function default(def : 'a, o : option('a)) : 'a = match(def, (x) => x, o)
|
||||||
|
|
||||||
|
/** Assume it is `Some`
|
||||||
|
*/
|
||||||
function force(o : option('a)) : 'a = default(abort("Forced None value"), o)
|
function force(o : option('a)) : 'a = default(abort("Forced None value"), o)
|
||||||
|
|
||||||
function on_elem(o : option('a), f : 'a => unit) : unit = match((), f, o)
|
function on_elem(o : option('a), f : 'a => unit) : unit = match((), f, o)
|
||||||
@ -40,10 +45,14 @@ namespace Option =
|
|||||||
(Some(x1), Some(x2), Some(x3)) => Some(f(x1, x2, x3))
|
(Some(x1), Some(x2), Some(x3)) => Some(f(x1, x2, x3))
|
||||||
_ => None
|
_ => None
|
||||||
|
|
||||||
|
/** Like `map`, but the function is in `option`
|
||||||
|
*/
|
||||||
function app_over(f : option ('a => 'b), o : option('a)) : option('b) = switch((f, o))
|
function app_over(f : option ('a => 'b), o : option('a)) : option('b) = switch((f, o))
|
||||||
(Some(ff), Some(xx)) => Some(ff(xx))
|
(Some(ff), Some(xx)) => Some(ff(xx))
|
||||||
_ => None
|
_ => None
|
||||||
|
|
||||||
|
/** Monadic bind
|
||||||
|
*/
|
||||||
function flat_map(f : 'a => option('b), o : option('a)) : option('b) = switch(o)
|
function flat_map(f : 'a => option('b), o : option('a)) : option('b) = switch(o)
|
||||||
None => None
|
None => None
|
||||||
Some(x) => f(x)
|
Some(x) => f(x)
|
||||||
@ -53,11 +62,17 @@ namespace Option =
|
|||||||
None => []
|
None => []
|
||||||
Some(x) => [x]
|
Some(x) => [x]
|
||||||
|
|
||||||
|
/** Turns list of options into a list of elements that are under `Some`s.
|
||||||
|
* Safe.
|
||||||
|
*/
|
||||||
function filter_options(l : list(option('a))) : list('a) = switch(l)
|
function filter_options(l : list(option('a))) : list('a) = switch(l)
|
||||||
[] => []
|
[] => []
|
||||||
None::t => filter_options(t)
|
None::t => filter_options(t)
|
||||||
Some(x)::t => x::filter_options(t)
|
Some(x)::t => x::filter_options(t)
|
||||||
|
|
||||||
|
/** Just like `filter_options` but requires all elements to be `Some` and returns
|
||||||
|
* None if any of them is not
|
||||||
|
*/
|
||||||
function seq_options(l : list (option('a))) : option (list('a)) = switch(l)
|
function seq_options(l : list (option('a))) : option (list('a)) = switch(l)
|
||||||
[] => Some([])
|
[] => Some([])
|
||||||
None::_ => None
|
None::_ => None
|
||||||
@ -66,11 +81,14 @@ namespace Option =
|
|||||||
Some(st) => Some(x::st)
|
Some(st) => Some(x::st)
|
||||||
|
|
||||||
|
|
||||||
|
/** Choose `Some` out of two if possible
|
||||||
|
*/
|
||||||
function choose(o1 : option('a), o2 : option('a)) : option('a) =
|
function choose(o1 : option('a), o2 : option('a)) : option('a) =
|
||||||
if(is_some(o1)) o1 else o2
|
if(is_some(o1)) o1 else o2
|
||||||
|
|
||||||
|
/** Choose `Some` from list of options if possible
|
||||||
|
*/
|
||||||
function choose_first(l : list(option('a))) : option('a) = switch(l)
|
function choose_first(l : list(option('a))) : option('a) = switch(l)
|
||||||
[] => None
|
[] => None
|
||||||
None::t => choose_first(t)
|
None::t => choose_first(t)
|
||||||
Some(x)::_ => Some(x)
|
Some(x)::_ => Some(x)
|
||||||
|
|
||||||
|
@ -6,12 +6,18 @@ namespace Pair =
|
|||||||
function snd(t : ('a * 'b)) : 'b = switch(t)
|
function snd(t : ('a * 'b)) : 'b = switch(t)
|
||||||
(_, y) => y
|
(_, y) => y
|
||||||
|
|
||||||
|
/** Map over first
|
||||||
|
*/
|
||||||
function map1(f : 'a => 'c, t : ('a * 'b)) : ('c * 'b) = switch(t)
|
function map1(f : 'a => 'c, t : ('a * 'b)) : ('c * 'b) = switch(t)
|
||||||
(x, y) => (f(x), y)
|
(x, y) => (f(x), y)
|
||||||
|
|
||||||
|
/** Map over second
|
||||||
|
*/
|
||||||
function map2(f : 'b => 'c, t : ('a * 'b)) : ('a * 'c) = switch(t)
|
function map2(f : 'b => 'c, t : ('a * 'b)) : ('a * 'c) = switch(t)
|
||||||
(x, y) => (x, f(y))
|
(x, y) => (x, f(y))
|
||||||
|
|
||||||
|
/** Map over both
|
||||||
|
*/
|
||||||
function bimap(f : 'a => 'c, g : 'b => 'd, t : ('a * 'b)) : ('c * 'd) = switch(t)
|
function bimap(f : 'a => 'c, g : 'b => 'd, t : ('a * 'b)) : ('c * 'd) = switch(t)
|
||||||
(x, y) => (f(x), g(y))
|
(x, y) => (f(x), g(y))
|
||||||
|
|
||||||
|
@ -10,15 +10,23 @@ namespace Triple =
|
|||||||
(_, _, z) => z
|
(_, _, z) => z
|
||||||
|
|
||||||
|
|
||||||
|
/** Map over first
|
||||||
|
*/
|
||||||
function map1(f : 'a => 'm, t : ('a * 'b * 'c)) : ('m * 'b * 'c) = switch(t)
|
function map1(f : 'a => 'm, t : ('a * 'b * 'c)) : ('m * 'b * 'c) = switch(t)
|
||||||
(x, y, z) => (f(x), y, z)
|
(x, y, z) => (f(x), y, z)
|
||||||
|
|
||||||
|
/** Map over second
|
||||||
|
*/
|
||||||
function map2(f : 'b => 'm, t : ('a * 'b * 'c)) : ('a * 'm * 'c) = switch(t)
|
function map2(f : 'b => 'm, t : ('a * 'b * 'c)) : ('a * 'm * 'c) = switch(t)
|
||||||
(x, y, z) => (x, f(y), z)
|
(x, y, z) => (x, f(y), z)
|
||||||
|
|
||||||
|
/** Map over third
|
||||||
|
*/
|
||||||
function map3(f : 'c => 'm, t : ('a * 'b * 'c)) : ('a * 'b * 'm) = switch(t)
|
function map3(f : 'c => 'm, t : ('a * 'b * 'c)) : ('a * 'b * 'm) = switch(t)
|
||||||
(x, y, z) => (x, y, f(z))
|
(x, y, z) => (x, y, f(z))
|
||||||
|
|
||||||
|
/** Map over all elements
|
||||||
|
*/
|
||||||
function trimap( f : 'a => 'x
|
function trimap( f : 'a => 'x
|
||||||
, g : 'b => 'y
|
, g : 'b => 'y
|
||||||
, h : 'c => 'z
|
, h : 'c => 'z
|
||||||
@ -29,9 +37,13 @@ namespace Triple =
|
|||||||
function swap(t : ('a * 'b * 'c)) : ('c * 'b * 'a) = switch(t)
|
function swap(t : ('a * 'b * 'c)) : ('c * 'b * 'a) = switch(t)
|
||||||
(x, y, z) => (z, y, x)
|
(x, y, z) => (z, y, x)
|
||||||
|
|
||||||
|
/** Right rotation
|
||||||
|
*/
|
||||||
function rotr(t : ('a * 'b * 'c)) : ('c * 'a * 'b) = switch(t)
|
function rotr(t : ('a * 'b * 'c)) : ('c * 'a * 'b) = switch(t)
|
||||||
(x, y, z) => (z, x, y)
|
(x, y, z) => (z, x, y)
|
||||||
|
|
||||||
|
/** Left rotation
|
||||||
|
*/
|
||||||
function rotl(t : ('a * 'b * 'c)) : ('b * 'c * 'a) = switch(t)
|
function rotl(t : ('a * 'b * 'c)) : ('b * 'c * 'a) = switch(t)
|
||||||
(x, y, z) => (y, z, x)
|
(x, y, z) => (y, z, x)
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
|
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
{relx, [{release, {aesophia, "4.2.0"},
|
{relx, [{release, {aesophia, "4.3.0"},
|
||||||
[aesophia, aebytecode, getopt]},
|
[aesophia, aebytecode, getopt]},
|
||||||
|
|
||||||
{dev_mode, true},
|
{dev_mode, true},
|
||||||
|
@ -194,6 +194,8 @@ 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 ->
|
||||||
aeser_api_encoder:encode(Lit, L);
|
aeser_api_encoder:encode(Lit, L);
|
||||||
|
encode_expr({app, _, {'-', _}, [{int, _, N}]}) ->
|
||||||
|
encode_expr({int, [], -N});
|
||||||
encode_expr({app, _, F, As}) ->
|
encode_expr({app, _, F, As}) ->
|
||||||
Ef = encode_expr(F),
|
Ef = encode_expr(F),
|
||||||
Eas = encode_exprs(As),
|
Eas = encode_exprs(As),
|
||||||
|
@ -12,7 +12,11 @@
|
|||||||
|
|
||||||
-module(aeso_ast_infer_types).
|
-module(aeso_ast_infer_types).
|
||||||
|
|
||||||
-export([infer/1, infer/2, unfold_types_in_type/3]).
|
-export([ infer/1
|
||||||
|
, infer/2
|
||||||
|
, unfold_types_in_type/3
|
||||||
|
, pp_type/2
|
||||||
|
]).
|
||||||
|
|
||||||
-type utype() :: {fun_t, aeso_syntax:ann(), named_args_t(), [utype()], utype()}
|
-type utype() :: {fun_t, aeso_syntax:ann(), named_args_t(), [utype()], utype()}
|
||||||
| {app_t, aeso_syntax:ann(), utype(), [utype()]}
|
| {app_t, aeso_syntax:ann(), utype(), [utype()]}
|
||||||
@ -2253,7 +2257,8 @@ unify1(_Env, {bytes_t, _, Len}, {bytes_t, _, Len}, _When) ->
|
|||||||
unify1(Env, {if_t, _, {id, _, Id}, Then1, Else1}, {if_t, _, {id, _, Id}, Then2, Else2}, When) ->
|
unify1(Env, {if_t, _, {id, _, Id}, Then1, Else1}, {if_t, _, {id, _, Id}, Then2, Else2}, When) ->
|
||||||
unify(Env, Then1, Then2, When) andalso
|
unify(Env, Then1, Then2, When) andalso
|
||||||
unify(Env, Else1, Else2, When);
|
unify(Env, Else1, Else2, When);
|
||||||
unify1(Env, {fun_t, _, Named1, Args1, Result1}, {fun_t, _, Named2, Args2, Result2}, When) ->
|
unify1(Env, {fun_t, _, Named1, Args1, Result1}, {fun_t, _, Named2, Args2, Result2}, When)
|
||||||
|
when length(Args1) == length(Args2) ->
|
||||||
unify(Env, Named1, Named2, When) andalso
|
unify(Env, Named1, Named2, When) andalso
|
||||||
unify(Env, Args1, Args2, When) andalso unify(Env, Result1, Result2, When);
|
unify(Env, Args1, Args2, When) andalso unify(Env, Result1, Result2, When);
|
||||||
unify1(Env, {app_t, _, {Tag, _, F}, Args1}, {app_t, _, {Tag, _, F}, Args2}, When)
|
unify1(Env, {app_t, _, {Tag, _, F}, Args1}, {app_t, _, {Tag, _, F}, Args2}, When)
|
||||||
@ -2444,6 +2449,24 @@ mk_t_err(Pos, Msg) ->
|
|||||||
mk_t_err(Pos, Msg, Ctxt) ->
|
mk_t_err(Pos, Msg, Ctxt) ->
|
||||||
aeso_errors:new(type_error, Pos, lists:flatten(Msg), lists:flatten(Ctxt)).
|
aeso_errors:new(type_error, Pos, lists:flatten(Msg), lists:flatten(Ctxt)).
|
||||||
|
|
||||||
|
mk_error({higher_kinded_typevar, T}) ->
|
||||||
|
Msg = io_lib:format("Type ~s is a higher kinded type variable\n"
|
||||||
|
"(takes another type as an argument)\n", [pp(instantiate(T))]
|
||||||
|
),
|
||||||
|
mk_t_err(pos(T), Msg);
|
||||||
|
mk_error({wrong_type_arguments, X, ArityGiven, ArityReal}) ->
|
||||||
|
Msg = io_lib:format("Arity for ~s doesn't match. Expected ~p, got ~p\n"
|
||||||
|
, [pp(instantiate(X)), ArityReal, ArityGiven]
|
||||||
|
),
|
||||||
|
mk_t_err(pos(X), Msg);
|
||||||
|
mk_error({unnamed_map_update_with_default, Upd}) ->
|
||||||
|
Msg = "Invalid map update with default\n",
|
||||||
|
mk_t_err(pos(Upd), Msg);
|
||||||
|
mk_error({fundecl_must_have_funtype, _Ann, Id, Type}) ->
|
||||||
|
Msg = io_lib:format("~s at ~s was declared with an invalid type ~s.\n"
|
||||||
|
"Entrypoints and functions must have functional types"
|
||||||
|
, [pp(Id), pp_loc(Id), pp(instantiate(Type))]),
|
||||||
|
mk_t_err(pos(Id), Msg);
|
||||||
mk_error({cannot_unify, A, B, When}) ->
|
mk_error({cannot_unify, A, B, When}) ->
|
||||||
Msg = io_lib:format("Cannot unify ~s\n and ~s\n",
|
Msg = io_lib:format("Cannot unify ~s\n and ~s\n",
|
||||||
[pp(instantiate(A)), pp(instantiate(B))]),
|
[pp(instantiate(A)), pp(instantiate(B))]),
|
||||||
@ -2526,14 +2549,6 @@ mk_error({indexed_type_must_be_word, Type, Type1}) ->
|
|||||||
Msg = io_lib:format("The indexed type ~s (at ~s) equals ~s which is not a word type\n",
|
Msg = io_lib:format("The indexed type ~s (at ~s) equals ~s which is not a word type\n",
|
||||||
[pp_type("", Type), pp_loc(Type), pp_type("", Type1)]),
|
[pp_type("", Type), pp_loc(Type), pp_type("", Type1)]),
|
||||||
mk_t_err(pos(Type), Msg);
|
mk_t_err(pos(Type), Msg);
|
||||||
mk_error({payload_type_must_be_string, Type, Type}) ->
|
|
||||||
Msg = io_lib:format("The payload type ~s (at ~s) should be string\n",
|
|
||||||
[pp_type("", Type), pp_loc(Type)]),
|
|
||||||
mk_t_err(pos(Type), Msg);
|
|
||||||
mk_error({payload_type_must_be_string, Type, Type1}) ->
|
|
||||||
Msg = io_lib:format("The payload type ~s (at ~s) equals ~s but it should be string\n",
|
|
||||||
[pp_type("", Type), pp_loc(Type), pp_type("", Type1)]),
|
|
||||||
mk_t_err(pos(Type), Msg);
|
|
||||||
mk_error({event_0_to_3_indexed_values, Constr}) ->
|
mk_error({event_0_to_3_indexed_values, Constr}) ->
|
||||||
Msg = io_lib:format("The event constructor ~s (at ~s) has too many indexed values (max 3)\n",
|
Msg = io_lib:format("The event constructor ~s (at ~s) has too many indexed values (max 3)\n",
|
||||||
[name(Constr), pp_loc(Constr)]),
|
[name(Constr), pp_loc(Constr)]),
|
||||||
@ -2577,13 +2592,21 @@ mk_error({include, _, {string, Pos, Name}}) ->
|
|||||||
[binary_to_list(Name), pp_loc(Pos)]),
|
[binary_to_list(Name), pp_loc(Pos)]),
|
||||||
mk_t_err(pos(Pos), Msg);
|
mk_t_err(pos(Pos), Msg);
|
||||||
mk_error({namespace, _Pos, {con, Pos, Name}, _Def}) ->
|
mk_error({namespace, _Pos, {con, Pos, Name}, _Def}) ->
|
||||||
Msg = io_lib:format("Nested namespace not allowed\nNamespace '~s' at ~s not defined at top level.\n",
|
Msg = io_lib:format("Nested namespaces are not allowed\nNamespace '~s' at ~s not defined at top level.\n",
|
||||||
|
[Name, pp_loc(Pos)]),
|
||||||
|
mk_t_err(pos(Pos), Msg);
|
||||||
|
mk_error({contract, _Pos, {con, Pos, Name}, _Def}) ->
|
||||||
|
Msg = io_lib:format("Nested contracts are not allowed\nContract '~s' at ~s not defined at top level.\n",
|
||||||
|
[Name, pp_loc(Pos)]),
|
||||||
|
mk_t_err(pos(Pos), Msg);
|
||||||
|
mk_error({type_decl, _, {id, Pos, Name}, _}) ->
|
||||||
|
Msg = io_lib:format("Empty type declarations are not supported\nType ~s at ~s lacks a definition\n",
|
||||||
|
[Name, pp_loc(Pos)]),
|
||||||
|
mk_t_err(pos(Pos), Msg);
|
||||||
|
mk_error({letval, _Pos, {id, Pos, Name}, _Def}) ->
|
||||||
|
Msg = io_lib:format("Toplevel \"let\" definitions are not supported\nValue ~s at ~s could be replaced by 0-argument function\n",
|
||||||
[Name, pp_loc(Pos)]),
|
[Name, pp_loc(Pos)]),
|
||||||
mk_t_err(pos(Pos), Msg);
|
mk_t_err(pos(Pos), Msg);
|
||||||
mk_error({repeated_arg, Fun, Arg}) ->
|
|
||||||
Msg = io_lib:format("Repeated argument ~s to function ~s (at ~s).\n",
|
|
||||||
[Arg, pp(Fun), pp_loc(Fun)]),
|
|
||||||
mk_t_err(pos(Fun), Msg);
|
|
||||||
mk_error({stateful_not_allowed, Id, Fun}) ->
|
mk_error({stateful_not_allowed, Id, Fun}) ->
|
||||||
Msg = io_lib:format("Cannot reference stateful function ~s (at ~s)\nin the definition of non-stateful function ~s.\n",
|
Msg = io_lib:format("Cannot reference stateful function ~s (at ~s)\nin the definition of non-stateful function ~s.\n",
|
||||||
[pp(Id), pp_loc(Id), pp(Fun)]),
|
[pp(Id), pp_loc(Id), pp(Fun)]),
|
||||||
|
@ -347,7 +347,6 @@ decls_to_fcode(Env, Decls) ->
|
|||||||
end, Env1, Decls).
|
end, Env1, Decls).
|
||||||
|
|
||||||
-spec decl_to_fcode(env(), aeso_syntax:decl()) -> env().
|
-spec decl_to_fcode(env(), aeso_syntax:decl()) -> env().
|
||||||
decl_to_fcode(Env, {type_decl, _, _, _}) -> Env;
|
|
||||||
decl_to_fcode(Env = #{context := {main_contract, _}}, {fun_decl, _, Id, _}) ->
|
decl_to_fcode(Env = #{context := {main_contract, _}}, {fun_decl, _, Id, _}) ->
|
||||||
case is_no_code(Env) of
|
case is_no_code(Env) of
|
||||||
false -> fcode_error({missing_definition, Id});
|
false -> fcode_error({missing_definition, Id});
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
| pp_assembler
|
| pp_assembler
|
||||||
| pp_bytecode
|
| pp_bytecode
|
||||||
| no_code
|
| no_code
|
||||||
|
| keep_included
|
||||||
| {backend, aevm | fate}
|
| {backend, aevm | fate}
|
||||||
| {include, {file_system, [string()]} |
|
| {include, {file_system, [string()]} |
|
||||||
{explicit_files, #{string() => binary()}}}
|
{explicit_files, #{string() => binary()}}}
|
||||||
@ -336,12 +337,12 @@ to_sophia_value(ContractString, FunName, ok, Data, Options0) ->
|
|||||||
try
|
try
|
||||||
{ok, aeso_vm_decode:from_fate(Type, aeb_fate_encoding:deserialize(Data))}
|
{ok, aeso_vm_decode:from_fate(Type, aeb_fate_encoding:deserialize(Data))}
|
||||||
catch throw:cannot_translate_to_sophia ->
|
catch throw:cannot_translate_to_sophia ->
|
||||||
Type1 = prettypr:format(aeso_pretty:type(Type)),
|
Type1 = prettypr:format(aeso_pretty:type(Type0)),
|
||||||
Msg = io_lib:format("Cannot translate FATE value ~p\n of Sophia type ~s\n",
|
Msg = io_lib:format("Cannot translate FATE value ~p\n of Sophia type ~s\n",
|
||||||
[aeb_fate_encoding:deserialize(Data), Type1]),
|
[aeb_fate_encoding:deserialize(Data), Type1]),
|
||||||
{error, [aeso_errors:new(data_error, Msg)]};
|
{error, [aeso_errors:new(data_error, Msg)]};
|
||||||
_:_ ->
|
_:_ ->
|
||||||
Type1 = prettypr:format(aeso_pretty:type(Type)),
|
Type1 = prettypr:format(aeso_pretty:type(Type0)),
|
||||||
Msg = io_lib:format("Failed to decode binary as type ~s\n", [Type1]),
|
Msg = io_lib:format("Failed to decode binary as type ~s\n", [Type1]),
|
||||||
{error, [aeso_errors:new(data_error, Msg)]}
|
{error, [aeso_errors:new(data_error, Msg)]}
|
||||||
end
|
end
|
||||||
@ -650,8 +651,9 @@ pp_fate_type(T) -> io_lib:format("~w", [T]).
|
|||||||
|
|
||||||
%% -------------------------------------------------------------------
|
%% -------------------------------------------------------------------
|
||||||
|
|
||||||
|
-spec sophia_type_to_typerep(string()) -> {error, bad_type} | {ok, aeb_aevm_data:type()}.
|
||||||
sophia_type_to_typerep(String) ->
|
sophia_type_to_typerep(String) ->
|
||||||
{ok, Ast} = aeso_parser:type(String),
|
Ast = aeso_parser:run_parser(aeso_parser:type(), String),
|
||||||
try aeso_ast_to_icode:ast_typerep(Ast) of
|
try aeso_ast_to_icode:ast_typerep(Ast) of
|
||||||
Type -> {ok, Type}
|
Type -> {ok, Type}
|
||||||
catch _:_ -> {error, bad_type}
|
catch _:_ -> {error, bad_type}
|
||||||
|
@ -3,20 +3,33 @@
|
|||||||
%%% Description :
|
%%% Description :
|
||||||
%%% Created : 1 Mar 2018 by Ulf Norell
|
%%% Created : 1 Mar 2018 by Ulf Norell
|
||||||
-module(aeso_parser).
|
-module(aeso_parser).
|
||||||
|
-compile({no_auto_import,[map_get/2]}).
|
||||||
|
|
||||||
-export([string/1,
|
-export([string/1,
|
||||||
string/2,
|
string/2,
|
||||||
string/3,
|
string/3,
|
||||||
|
auto_imports/1,
|
||||||
hash_include/2,
|
hash_include/2,
|
||||||
type/1]).
|
decl/0,
|
||||||
|
type/0,
|
||||||
|
body/0,
|
||||||
|
maybe_block/1,
|
||||||
|
run_parser/2,
|
||||||
|
run_parser/3]).
|
||||||
|
|
||||||
-include("aeso_parse_lib.hrl").
|
-include("aeso_parse_lib.hrl").
|
||||||
-import(aeso_parse_lib, [current_file/0, set_current_file/1]).
|
-import(aeso_parse_lib, [current_file/0, set_current_file/1]).
|
||||||
|
|
||||||
-type parse_result() :: aeso_syntax:ast() | none().
|
-type parse_result() :: aeso_syntax:ast() | {aeso_syntax:ast(), sets:set(include_hash())} | none().
|
||||||
|
|
||||||
-type include_hash() :: {string(), binary()}.
|
-type include_hash() :: {string(), binary()}.
|
||||||
|
|
||||||
|
|
||||||
|
escape_errors({ok, Ok}) ->
|
||||||
|
Ok;
|
||||||
|
escape_errors({error, Err}) ->
|
||||||
|
parse_error(Err).
|
||||||
|
|
||||||
-spec string(string()) -> parse_result().
|
-spec string(string()) -> parse_result().
|
||||||
string(String) ->
|
string(String) ->
|
||||||
string(String, sets:new(), []).
|
string(String, sets:new(), []).
|
||||||
@ -30,21 +43,17 @@ string(String, Opts) ->
|
|||||||
|
|
||||||
-spec string(string(), sets:set(include_hash()), aeso_compiler:options()) -> parse_result().
|
-spec string(string(), sets:set(include_hash()), aeso_compiler:options()) -> parse_result().
|
||||||
string(String, Included, Opts) ->
|
string(String, Included, Opts) ->
|
||||||
case parse_and_scan(file(), String, Opts) of
|
AST = run_parser(file(), String, Opts),
|
||||||
{ok, AST} ->
|
case expand_includes(AST, Included, Opts) of
|
||||||
case expand_includes(AST, Included, Opts) of
|
{ok, AST1} -> AST1;
|
||||||
{ok, AST1} -> AST1;
|
{error, Err} -> parse_error(Err)
|
||||||
{error, Err} -> parse_error(Err)
|
|
||||||
end;
|
|
||||||
{error, Err} ->
|
|
||||||
parse_error(Err)
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
type(String) ->
|
|
||||||
case parse_and_scan(type(), String, []) of
|
run_parser(P, Inp) ->
|
||||||
{ok, AST} -> {ok, AST};
|
escape_errors(parse_and_scan(P, Inp, [])).
|
||||||
{error, Err} -> {error, [mk_error(Err)]}
|
run_parser(P, Inp, Opts) ->
|
||||||
end.
|
escape_errors(parse_and_scan(P, Inp, Opts)).
|
||||||
|
|
||||||
parse_and_scan(P, S, Opts) ->
|
parse_and_scan(P, S, Opts) ->
|
||||||
set_current_file(proplists:get_value(src_file, Opts, no_file)),
|
set_current_file(proplists:get_value(src_file, Opts, no_file)),
|
||||||
@ -102,7 +111,7 @@ decl() ->
|
|||||||
|
|
||||||
%% Function declarations
|
%% Function declarations
|
||||||
, ?RULE(modifiers(), fun_or_entry(), maybe_block(fundef_or_decl()), fun_block(_1, _2, _3))
|
, ?RULE(modifiers(), fun_or_entry(), maybe_block(fundef_or_decl()), fun_block(_1, _2, _3))
|
||||||
, ?RULE(keyword('let'), valdef(),set_pos(get_pos(_1), _2))
|
, ?RULE(keyword('let'), valdef(), set_pos(get_pos(_1), _2))
|
||||||
])).
|
])).
|
||||||
|
|
||||||
fun_block(Mods, Kind, [Decl]) ->
|
fun_block(Mods, Kind, [Decl]) ->
|
||||||
@ -596,8 +605,13 @@ expand_includes(AST, Included, Opts) ->
|
|||||||
|| File <- lists:usort(auto_imports(AST)) ] ++ AST,
|
|| File <- lists:usort(auto_imports(AST)) ] ++ AST,
|
||||||
expand_includes(AST1, Included, [], Opts).
|
expand_includes(AST1, Included, [], Opts).
|
||||||
|
|
||||||
expand_includes([], _Included, Acc, _Opts) ->
|
expand_includes([], Included, Acc, Opts) ->
|
||||||
{ok, lists:reverse(Acc)};
|
case lists:member(keep_included, Opts) of
|
||||||
|
false ->
|
||||||
|
{ok, lists:reverse(Acc)};
|
||||||
|
true ->
|
||||||
|
{ok, {lists:reverse(Acc), Included}}
|
||||||
|
end;
|
||||||
expand_includes([{include, Ann, {string, _SAnn, File}} | AST], Included, Acc, Opts) ->
|
expand_includes([{include, Ann, {string, _SAnn, File}} | AST], Included, Acc, Opts) ->
|
||||||
case get_include_code(File, Ann, Opts) of
|
case get_include_code(File, Ann, Opts) of
|
||||||
{ok, Code} ->
|
{ok, Code} ->
|
||||||
@ -656,8 +670,14 @@ stdlib_options() ->
|
|||||||
|
|
||||||
get_include_code(File, Ann, Opts) ->
|
get_include_code(File, Ann, Opts) ->
|
||||||
case {read_file(File, Opts), read_file(File, stdlib_options())} of
|
case {read_file(File, Opts), read_file(File, stdlib_options())} of
|
||||||
{{ok, _}, {ok,_ }} ->
|
{{ok, Bin}, {ok, _}} ->
|
||||||
fail(ann_pos(Ann), "Illegal redefinition of standard library " ++ File);
|
case filename:basename(File) == File of
|
||||||
|
true -> { error
|
||||||
|
, fail( ann_pos(Ann)
|
||||||
|
, "Illegal redefinition of standard library " ++ binary_to_list(File))};
|
||||||
|
%% If a path is provided then the stdlib takes lower priority
|
||||||
|
false -> {ok, binary_to_list(Bin)}
|
||||||
|
end;
|
||||||
{_, {ok, Bin}} ->
|
{_, {ok, Bin}} ->
|
||||||
{ok, binary_to_list(Bin)};
|
{ok, binary_to_list(Bin)};
|
||||||
{{ok, Bin}, _} ->
|
{{ok, Bin}, _} ->
|
||||||
|
@ -145,8 +145,12 @@ 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(aeso_syntax:decl()) -> doc().
|
||||||
decl({contract, _, C, Ds}) ->
|
decl({contract, Attrs, C, Ds}) ->
|
||||||
block(follow(text("contract"), hsep(name(C), text("="))), decls(Ds));
|
Mod = fun({Mod, true}) when Mod == payable ->
|
||||||
|
text(atom_to_list(Mod));
|
||||||
|
(_) -> empty() end,
|
||||||
|
block(follow( hsep(lists:map(Mod, Attrs) ++ [text("contract")])
|
||||||
|
, hsep(name(C), text("="))), decls(Ds));
|
||||||
decl({namespace, _, C, Ds}) ->
|
decl({namespace, _, C, Ds}) ->
|
||||||
block(follow(text("namespace"), hsep(name(C), text("="))), decls(Ds));
|
block(follow(text("namespace"), hsep(name(C), text("="))), decls(Ds));
|
||||||
decl({pragma, _, Pragma}) -> pragma(Pragma);
|
decl({pragma, _, Pragma}) -> pragma(Pragma);
|
||||||
@ -155,13 +159,16 @@ decl({type_def, _, T, Vars, Def}) ->
|
|||||||
Kind = element(1, Def),
|
Kind = element(1, Def),
|
||||||
equals(typedecl(Kind, T, Vars), typedef(Def));
|
equals(typedecl(Kind, T, Vars), typedef(Def));
|
||||||
decl({fun_decl, Ann, F, T}) ->
|
decl({fun_decl, Ann, F, T}) ->
|
||||||
|
Mod = fun({Mod, true}) when Mod == private; Mod == stateful; Mod == payable ->
|
||||||
|
text(atom_to_list(Mod));
|
||||||
|
(_) -> empty() end,
|
||||||
Fun = case aeso_syntax:get_ann(entrypoint, Ann, false) of
|
Fun = case aeso_syntax:get_ann(entrypoint, Ann, false) of
|
||||||
true -> text("entrypoint");
|
true -> text("entrypoint");
|
||||||
false -> text("function")
|
false -> text("function")
|
||||||
end,
|
end,
|
||||||
hsep(Fun, typed(name(F), T));
|
hsep(lists:map(Mod, Ann) ++ [Fun, typed(name(F), T)]);
|
||||||
decl(D = {letfun, Attrs, _, _, _, _}) ->
|
decl(D = {letfun, Attrs, _, _, _, _}) ->
|
||||||
Mod = fun({Mod, true}) when Mod == private; Mod == stateful ->
|
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 aeso_syntax:get_ann(entrypoint, Attrs, false) of
|
||||||
@ -363,7 +370,8 @@ expr_p(_, {Type, _, Bin})
|
|||||||
Type == oracle_query_id ->
|
Type == oracle_query_id ->
|
||||||
text(binary_to_list(aeser_api_encoder:encode(Type, Bin)));
|
text(binary_to_list(aeser_api_encoder:encode(Type, Bin)));
|
||||||
expr_p(_, {string, _, <<>>}) -> text("\"\"");
|
expr_p(_, {string, _, <<>>}) -> text("\"\"");
|
||||||
expr_p(_, {string, _, S}) -> term(binary_to_list(S));
|
expr_p(_, {string, _, S}) ->
|
||||||
|
text(io_lib:format("\"~s\"", [binary_to_list(S)]));
|
||||||
expr_p(_, {char, _, C}) ->
|
expr_p(_, {char, _, C}) ->
|
||||||
case C of
|
case C of
|
||||||
$' -> text("'\\''");
|
$' -> text("'\\''");
|
||||||
@ -490,6 +498,3 @@ get_elifs(If = {'if', Ann, Cond, Then, Else}, Elifs) ->
|
|||||||
end;
|
end;
|
||||||
get_elifs(Else, Elifs) -> {lists:reverse(Elifs), {else, Else}}.
|
get_elifs(Else, Elifs) -> {lists:reverse(Elifs), {else, Else}}.
|
||||||
|
|
||||||
fmt(Fmt, Args) -> text(lists:flatten(io_lib:format(Fmt, Args))).
|
|
||||||
term(X) -> fmt("~p", [X]).
|
|
||||||
|
|
||||||
|
@ -37,20 +37,24 @@
|
|||||||
-type decl() :: {contract, ann(), con(), [decl()]}
|
-type decl() :: {contract, ann(), con(), [decl()]}
|
||||||
| {namespace, ann(), con(), [decl()]}
|
| {namespace, ann(), con(), [decl()]}
|
||||||
| {pragma, ann(), pragma()}
|
| {pragma, ann(), pragma()}
|
||||||
| {type_decl, ann(), id(), [tvar()]}
|
| {type_decl, ann(), id(), [tvar()]} % Only for error msgs
|
||||||
| {type_def, ann(), id(), [tvar()], typedef()}
|
| {type_def, ann(), id(), [tvar()], typedef()}
|
||||||
| {fun_decl, ann(), id(), type()}
|
| {fun_decl, ann(), id(), type()}
|
||||||
| {fun_clauses, ann(), id(), type(), [letbind()]}
|
| {fun_clauses, ann(), id(), type(), [letbind()]}
|
||||||
| {block, ann(), [decl()]}
|
| {block, ann(), [decl()]}
|
||||||
| letbind().
|
| letfun()
|
||||||
|
| letval(). % Only for error msgs
|
||||||
|
|
||||||
-type compiler_version() :: [non_neg_integer()].
|
-type compiler_version() :: [non_neg_integer()].
|
||||||
|
|
||||||
-type pragma() :: {compiler, '==' | '<' | '>' | '=<' | '>=', compiler_version()}.
|
-type pragma() :: {compiler, '==' | '<' | '>' | '=<' | '>=', compiler_version()}.
|
||||||
|
|
||||||
|
|
||||||
|
-type letval() :: {letval, ann(), pat(), expr()}.
|
||||||
|
-type letfun() :: {letfun, ann(), id(), [pat()], type(), expr()}.
|
||||||
-type letbind()
|
-type letbind()
|
||||||
:: {letval, ann(), pat(), expr()}
|
:: letfun()
|
||||||
| {letfun, ann(), id(), [pat()], type(), expr()}.
|
| letval().
|
||||||
|
|
||||||
-type arg() :: {arg, ann(), id(), type()}.
|
-type arg() :: {arg, ann(), id(), type()}.
|
||||||
|
|
||||||
|
@ -45,7 +45,6 @@ fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) ->
|
|||||||
%% decl()
|
%% decl()
|
||||||
{contract, _, _, Ds} -> Decl(Ds);
|
{contract, _, _, Ds} -> Decl(Ds);
|
||||||
{namespace, _, _, Ds} -> Decl(Ds);
|
{namespace, _, _, Ds} -> Decl(Ds);
|
||||||
{type_decl, _, I, _} -> BindType(I);
|
|
||||||
{type_def, _, I, _, D} -> Plus(BindType(I), Decl(D));
|
{type_def, _, I, _, D} -> Plus(BindType(I), Decl(D));
|
||||||
{fun_decl, _, _, T} -> Type(T);
|
{fun_decl, _, _, T} -> Type(T);
|
||||||
{letval, _, P, E} -> Scoped(BindExpr(P), Expr(E));
|
{letval, _, P, E} -> Scoped(BindExpr(P), Expr(E));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{application, aesophia,
|
{application, aesophia,
|
||||||
[{description, "Contract Language for aeternity"},
|
[{description, "Contract Language for aeternity"},
|
||||||
{vsn, "4.2.0"},
|
{vsn, "4.3.0"},
|
||||||
{registered, []},
|
{registered, []},
|
||||||
{applications,
|
{applications,
|
||||||
[kernel,
|
[kernel,
|
||||||
|
@ -381,11 +381,15 @@ failing_contracts() ->
|
|||||||
" r.foo() : map(int, string)\n"
|
" r.foo() : map(int, string)\n"
|
||||||
"against the expected type\n"
|
"against the expected type\n"
|
||||||
" map(string, int)">>])
|
" map(string, int)">>])
|
||||||
, ?TYPE_ERROR(bad_include_and_ns,
|
, ?TYPE_ERROR(not_toplevel_include,
|
||||||
[<<?Pos(2, 11)
|
[<<?Pos(2, 11)
|
||||||
"Include of 'included.aes' at line 2, column 11\nnot allowed, include only allowed at top level.">>,
|
"Include of 'included.aes' at line 2, column 11\nnot allowed, include only allowed at top level.">>])
|
||||||
<<?Pos(3, 13)
|
, ?TYPE_ERROR(not_toplevel_namespace,
|
||||||
"Nested namespace not allowed\nNamespace 'Foo' at line 3, column 13 not defined at top level.">>])
|
[<<?Pos(2, 13)
|
||||||
|
"Nested namespaces are not allowed\nNamespace 'Foo' at line 2, column 13 not defined at top level.">>])
|
||||||
|
, ?TYPE_ERROR(not_toplevel_contract,
|
||||||
|
[<<?Pos(2, 12)
|
||||||
|
"Nested contracts are not allowed\nContract 'Con' at line 2, column 12 not defined at top level.">>])
|
||||||
, ?TYPE_ERROR(bad_address_literals,
|
, ?TYPE_ERROR(bad_address_literals,
|
||||||
[<<?Pos(11, 5)
|
[<<?Pos(11, 5)
|
||||||
"Cannot unify address\n"
|
"Cannot unify address\n"
|
||||||
@ -622,6 +626,44 @@ failing_contracts() ->
|
|||||||
[<<?Pos(5, 28)
|
[<<?Pos(5, 28)
|
||||||
"Invalid call to contract entrypoint 'Foo.foo'.\n"
|
"Invalid call to contract entrypoint 'Foo.foo'.\n"
|
||||||
"It must be called as 'c.foo' for some c : Foo.">>])
|
"It must be called as 'c.foo' for some c : Foo.">>])
|
||||||
|
, ?TYPE_ERROR(toplevel_let,
|
||||||
|
[<<?Pos(2, 7)
|
||||||
|
"Toplevel \"let\" definitions are not supported\n"
|
||||||
|
"Value this_is_illegal at line 2, column 7 could be replaced by 0-argument function">>])
|
||||||
|
, ?TYPE_ERROR(empty_typedecl,
|
||||||
|
[<<?Pos(2, 8)
|
||||||
|
"Empty type declarations are not supported\n"
|
||||||
|
"Type t at line 2, column 8 lacks a definition">>])
|
||||||
|
, ?TYPE_ERROR(higher_kinded_type,
|
||||||
|
[<<?Pos(2, 35)
|
||||||
|
"Type 'm is a higher kinded type variable\n"
|
||||||
|
"(takes another type as an argument)">>])
|
||||||
|
, ?TYPE_ERROR(bad_arity,
|
||||||
|
[<<?Pos(3, 20)
|
||||||
|
"Arity for id doesn't match. Expected 1, got 0">>,
|
||||||
|
<<?Pos(3, 25)
|
||||||
|
"Cannot unify int\n"
|
||||||
|
" and id\n"
|
||||||
|
"when checking the type of the expression at line 3, column 25\n"
|
||||||
|
" 123 : int\n"
|
||||||
|
"against the expected type\n"
|
||||||
|
" id">>,
|
||||||
|
<<?Pos(4, 20)
|
||||||
|
"Arity for id doesn't match. Expected 1, got 2">>,
|
||||||
|
<<?Pos(4, 35)
|
||||||
|
"Cannot unify int\n"
|
||||||
|
" and id(int, int)\n"
|
||||||
|
"when checking the type of the expression at line 4, column 35\n"
|
||||||
|
" 123 : int\n"
|
||||||
|
"against the expected type\n"
|
||||||
|
" id(int, int)">>])
|
||||||
|
, ?TYPE_ERROR(bad_unnamed_map_update_default,
|
||||||
|
[<<?Pos(4, 17)
|
||||||
|
"Invalid map update with default">>])
|
||||||
|
, ?TYPE_ERROR(non_functional_entrypoint,
|
||||||
|
[<<?Pos(2, 14)
|
||||||
|
"f at line 2, column 14 was declared with an invalid type int.\n"
|
||||||
|
"Entrypoints and functions must have functional types">>])
|
||||||
, ?TYPE_ERROR(bad_records,
|
, ?TYPE_ERROR(bad_records,
|
||||||
[<<?Pos(3, 16)
|
[<<?Pos(3, 16)
|
||||||
"Mixed record fields and map keys in\n"
|
"Mixed record fields and map keys in\n"
|
||||||
@ -639,6 +681,28 @@ failing_contracts() ->
|
|||||||
" (0 : int) == (1 : int) : bool\n"
|
" (0 : int) == (1 : int) : bool\n"
|
||||||
"It must be either 'true' or 'false'.">>
|
"It must be either 'true' or 'false'.">>
|
||||||
])
|
])
|
||||||
|
, ?TYPE_ERROR(bad_number_of_args,
|
||||||
|
[<<?Pos(3, 39)
|
||||||
|
"Cannot unify () => unit\n"
|
||||||
|
" and (int) => 'a\n",
|
||||||
|
"when checking the application at line 3, column 39 of\n"
|
||||||
|
" f : () => unit\n"
|
||||||
|
"to arguments\n"
|
||||||
|
" 1 : int">>,
|
||||||
|
<<?Pos(4, 20)
|
||||||
|
"Cannot unify (int, string) => 'e\n"
|
||||||
|
" and (int) => 'd\n"
|
||||||
|
"when checking the application at line 4, column 20 of\n"
|
||||||
|
" g : (int, string) => 'e\n"
|
||||||
|
"to arguments\n"
|
||||||
|
" 1 : int">>,
|
||||||
|
<<?Pos(5, 20)
|
||||||
|
"Cannot unify (int, string) => 'c\n"
|
||||||
|
" and (string) => 'b\n"
|
||||||
|
"when checking the application at line 5, column 20 of\n"
|
||||||
|
" g : (int, string) => 'c\nto arguments\n"
|
||||||
|
" \"Litwo, ojczyzno moja\" : string">>
|
||||||
|
])
|
||||||
].
|
].
|
||||||
|
|
||||||
-define(Path(File), "code_errors/" ??File).
|
-define(Path(File), "code_errors/" ??File).
|
||||||
|
@ -58,8 +58,7 @@ contract Greeter =
|
|||||||
|
|
||||||
let state = { greeting = "Hello" }
|
let state = { greeting = "Hello" }
|
||||||
|
|
||||||
let setGreeting =
|
function setGreeting(greeting: string) =
|
||||||
(greeting: string) =>
|
|
||||||
state{ greeting = greeting }
|
state{ greeting = greeting }
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,44 +1,82 @@
|
|||||||
// Try to cover all syntactic constructs.
|
// Try to cover all syntactic constructs.
|
||||||
|
@compiler > 0
|
||||||
|
@compiler =< 10.1.1.1.1.1.2.3.4
|
||||||
|
|
||||||
contract AllSyntaxType =
|
|
||||||
type typeDecl /* bla */
|
|
||||||
type paramTypeDecl('a, 'b)
|
|
||||||
|
|
||||||
|
namespace Ns =
|
||||||
|
datatype d('a) = D | S(int) | M('a, list('a), int)
|
||||||
|
private function fff() = 123
|
||||||
|
|
||||||
|
stateful entrypoint
|
||||||
|
f (1, x) = (_) => x
|
||||||
|
|
||||||
|
payable contract AllSyntaxType =
|
||||||
/** Multi-
|
/** Multi-
|
||||||
* line
|
* line
|
||||||
* comment
|
* comment
|
||||||
*/
|
*/
|
||||||
function foo : _
|
stateful function foo : _
|
||||||
|
entrypoint bar : int => (int * 'a)
|
||||||
|
|
||||||
|
|
||||||
contract AllSyntax =
|
contract AllSyntax =
|
||||||
|
|
||||||
type typeDecl = int
|
datatype mickiewicz = Adam | Mickiewicz
|
||||||
type paramTypeDecl('a, 'b) = (('a, 'b) => 'b) => list('a) => 'b => 'b
|
record goethe('a, 'b) = {
|
||||||
|
johann : int,
|
||||||
|
wolfgang : 'a,
|
||||||
|
von : 'a * 'b * int,
|
||||||
|
goethe : unit
|
||||||
|
}
|
||||||
|
type dante = Ns.d(int)
|
||||||
|
type shakespeare('a) = goethe('a, 'a)
|
||||||
|
|
||||||
record nestedRecord = { x : int }
|
type state = shakespeare(int)
|
||||||
record recordType = { z : nestedRecord, y : int }
|
|
||||||
datatype variantType('a) = None | Some('a)
|
|
||||||
|
|
||||||
let valWithType : map(int, int) => option(int) = (m) => Map.get(m, 42)
|
entrypoint init() = {
|
||||||
let valNoType =
|
johann = 1000,
|
||||||
if(valWithType(Map.empty) == None)
|
wolfgang = -10,
|
||||||
print(42 mod 10 * 5 / 3)
|
|
||||||
|
|
||||||
function funWithType(x : int, y) : int * list(int) = (x, 0 :: [y] ++ [])
|
/* TODO: This does not compile because of bug in the parser tester.
|
||||||
function funNoType() =
|
von = (2 + 2, 0, List.sum([x | k <- [1,2,3]
|
||||||
let foo = (x, y : bool) =>
|
, let l = k + 1
|
||||||
if (! (y && x =< 0x0b || true)) [x]
|
, if(l < 10)
|
||||||
else [11..20]
|
, let f(x) = x + 100
|
||||||
let setY(r : recordType) : unit = r{ y = 5 }
|
, Adam <- [Adam, Mickiewicz]
|
||||||
let setX(r : recordType, x : int) : recordType = r { z.x = x } // nested record update
|
, let x = f(l)
|
||||||
let getY(r) = switch(r) {y = y} => y
|
])),
|
||||||
switch (funWithType(1, -2))
|
*/
|
||||||
(x, [y, z]) => bar({x = z, y = -y + - -z * (-1)})
|
von = (2 + 2, 0, List.sum([1,2,3,4])),
|
||||||
(x, y :: _) => ()
|
goethe = () }
|
||||||
|
|
||||||
let hash : address = #01ab0fff11
|
function f() =
|
||||||
let b = false
|
let kp = "nietzsche"
|
||||||
let qcon = Mod.Con
|
// let p = "Пушкин" // TODO: this also doesn't do right round_trip...
|
||||||
let str = "blabla\nfoo"
|
let k(x : bytes(8)) : bytes(8) = Bytes.to_int(#fedcba9876543210)
|
||||||
let chr = '"'
|
|
||||||
|
|
||||||
|
let f : () => address = () => ak_2gx9MEFxKvY9vMG5YnqnXWv1hCsX7rgnfvBLJS4aQurustR1rt
|
||||||
|
if(Bits.test(Bits.all, 10))
|
||||||
|
abort("ohno")
|
||||||
|
if(true && false)
|
||||||
|
require(true, "ohyes")
|
||||||
|
elif(false || 2 == 2)
|
||||||
|
()
|
||||||
|
else
|
||||||
|
()
|
||||||
|
if(true) f(1,2)((1,2))
|
||||||
|
else switch(1::[1,2,3])
|
||||||
|
[] => 1
|
||||||
|
a::b => 123
|
||||||
|
1::2::3 => 123123
|
||||||
|
[2,3,4] => 1
|
||||||
|
_ => 13
|
||||||
|
1::[2] => 2138
|
||||||
|
put(state{johann = 1})
|
||||||
|
|
||||||
|
let m = {["foo"] = 19, /*hey wanna talk about inlined comments?*/ ["bar"] = 42}
|
||||||
|
let n = {}
|
||||||
|
m{ ["x" = 0] @ z = z + state.johann }
|
||||||
|
|
||||||
|
let sh : shakespeare(shakespeare(int)) =
|
||||||
|
{wolfgang = state}
|
||||||
|
sh{wolfgang.wolfgang = sh.wolfgang} // comment
|
||||||
|
4
test/contracts/bad_arity.aes
Normal file
4
test/contracts/bad_arity.aes
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
contract C =
|
||||||
|
type id('a) = 'a
|
||||||
|
entrypoint f() : id = 123
|
||||||
|
entrypoint g() : id(int, int) = 123
|
6
test/contracts/bad_number_of_args.aes
Normal file
6
test/contracts/bad_number_of_args.aes
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
contract Test =
|
||||||
|
entrypoint f() = ()
|
||||||
|
entrypoint g(x : int, y : string) = f(1)
|
||||||
|
entrypoint h() = g(1)
|
||||||
|
entrypoint i() = g("Litwo, ojczyzno moja")
|
||||||
|
|
5
test/contracts/bad_unnamed_map_update_default.aes
Normal file
5
test/contracts/bad_unnamed_map_update_default.aes
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
contract C =
|
||||||
|
entrypoint f() =
|
||||||
|
let z = 123
|
||||||
|
{}{ [1 = 0] = z + 1 }
|
||||||
|
2
|
3
test/contracts/empty_typedecl.aes
Normal file
3
test/contracts/empty_typedecl.aes
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
contract C =
|
||||||
|
type t
|
||||||
|
entrypoint f() = 123
|
3
test/contracts/higher_kinded_type.aes
Normal file
3
test/contracts/higher_kinded_type.aes
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
contract IWantToBelieve =
|
||||||
|
type stateT('s, 'm, 'a) = 's => 'm('a * 's)
|
||||||
|
entrypoint s() = 123
|
@ -15,7 +15,7 @@ contract MultiSig =
|
|||||||
| OwnerRemoved (address) // of { .removedOwner : Address }
|
| OwnerRemoved (address) // of { .removedOwner : Address }
|
||||||
| ReqChanged (int) // of { .newReq : int }
|
| ReqChanged (int) // of { .newReq : int }
|
||||||
|
|
||||||
let maxOwners : int = 250
|
function maxOwners() : int = 250
|
||||||
|
|
||||||
record state = { nRequired : int
|
record state = { nRequired : int
|
||||||
, nOwners : int
|
, nOwners : int
|
||||||
@ -68,7 +68,7 @@ contract MultiSig =
|
|||||||
switch(check_pending(callhash()))
|
switch(check_pending(callhash()))
|
||||||
CheckFail(state') => { state = state' }
|
CheckFail(state') => { state = state' }
|
||||||
CheckOk(state') =>
|
CheckOk(state') =>
|
||||||
if(state.nOwners >= maxOwners) () /* TODO */
|
if(state.nOwners >= maxOwners()) () /* TODO */
|
||||||
else
|
else
|
||||||
let nOwners' = state'.nOwners + 1
|
let nOwners' = state'.nOwners + 1
|
||||||
{ state = state' { owners = Map.insert(nOwners', newOwner, state'.owners)
|
{ state = state' { owners = Map.insert(nOwners', newOwner, state'.owners)
|
||||||
|
5
test/contracts/non_functional_entrypoint.aes
Normal file
5
test/contracts/non_functional_entrypoint.aes
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
contract C1 =
|
||||||
|
entrypoint f : int
|
||||||
|
|
||||||
|
contract C =
|
||||||
|
entrypoint f() = 123
|
6
test/contracts/not_toplevel_contract.aes
Normal file
6
test/contracts/not_toplevel_contract.aes
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
namespace BadNs =
|
||||||
|
contract Con =
|
||||||
|
entrypoint e : () => int
|
||||||
|
|
||||||
|
contract Con =
|
||||||
|
entrypoint foo() = 43
|
5
test/contracts/not_toplevel_include.aes
Normal file
5
test/contracts/not_toplevel_include.aes
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
namespace BadNs =
|
||||||
|
include "included.aes"
|
||||||
|
|
||||||
|
contract Con =
|
||||||
|
entrypoint foo() = 43
|
@ -1,5 +1,4 @@
|
|||||||
contract Bad =
|
contract BadCon =
|
||||||
include "included.aes"
|
|
||||||
namespace Foo =
|
namespace Foo =
|
||||||
function foo() = 42
|
function foo() = 42
|
||||||
|
|
3
test/contracts/toplevel_let.aes
Normal file
3
test/contracts/toplevel_let.aes
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
contract C =
|
||||||
|
let this_is_illegal = 2/0
|
||||||
|
entrypoint this_is_legal() = 2/0
|
@ -1,16 +1,3 @@
|
|||||||
|
|
||||||
/* Contract type */
|
|
||||||
contract VotingType =
|
|
||||||
type state
|
|
||||||
function init : list(string) => state
|
|
||||||
|
|
||||||
function giveRightToVote : address => unit
|
|
||||||
function delegate : address => unit
|
|
||||||
function vote : int => unit
|
|
||||||
function winnerName : unit => string
|
|
||||||
function currentTally : unit => list(string * int)
|
|
||||||
|
|
||||||
/* Contract implementation */
|
|
||||||
contract Voting =
|
contract Voting =
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
|
Loading…
x
Reference in New Issue
Block a user