Compare commits

..

12 Commits

Author SHA1 Message Date
Radosław Rowicki 962ddf5303 Version push – 4.3.0 (#255)
* Version push – 4.3.0

.

* Fixed ordering of diffs in CHANGELOG
2020-04-02 15:10:53 +02:00
Radosław Rowicki 85b151aa65 Prepare 4.3.0 (#254) 2020-04-02 13:59:22 +02:00
Radosław Rowicki 93341dc13b Prepared for REPL usage (#218)
* Prepared for REPL usage

Exposed expr parsing

ets init in constant

Exposing and fixing

exposed expr

This will be squashed either

Expose letdef

Error handling

exposed autoimport

remove unnecessary changes

Fix types

Parser update

Expose body parser

remove map_get warning

make dialyzer happy

* Formatting

Co-Authored-By: Hans Svensson <hanssv@gmail.com>

Co-authored-by: Hans Svensson <hanssv@gmail.com>
2020-04-02 12:29:14 +02:00
Radosław Rowicki 98036eff65 Update TOC in sophia.md (#245) 2020-04-01 13:11:02 +02:00
Radosław Rowicki dc977f7354 Fixed example (#249) 2020-03-31 13:14:13 +02:00
Radosław Rowicki 4f554acee6 Fix error messages for some illegal constructions, fix absolute path includes (#251)
* Updated tests, banned type decls and toplevel letvals

* Properly ban nested contracts

* Fix including by path

* Fix error message test

* Fix prettpr attr display. Make dialyzer happy

* More tests

* Fixed type printing

* Updated docs
2020-03-30 14:52:16 +02:00
Radosław Rowicki 48b52cb501 Enchanted Frac library a bit (#253) 2020-03-29 17:14:01 +02:00
Ulf Norell 515838e2f9 Handle negative numbers in aci (#247)
* Handle negative numbers in aci

Fixes aeternity/aesophia_http#59

* Updated CHANGELOG

Updated CHANGELOG1

Co-authored-by: radrow <radrowicki@gmail.com>
2020-03-23 18:11:00 +01:00
Radosław Rowicki 83e03f3013 Added documentation (#239)
* Added documentation

* Update readme

* Update readme

* Format fix

* Events

* Stdlib mention

* Frac doc

* Frac doc comparison warning

* Typos

* Format fix, TOC added

* Fixed link

* Update editor message

* Split TOC

* Moved out AEVM ABI

* Minor format

Co-Authored-By: Hans Svensson <hanssv@gmail.com>

* Typo

Co-Authored-By: Hans Svensson <hanssv@gmail.com>

* Grammar

Co-Authored-By: Hans Svensson <hanssv@gmail.com>

* Language

Co-authored-by: Hans Svensson <hanssv@gmail.com>
2020-03-10 12:39:39 +01:00
Radosław Rowicki d7fa4d65ec More comments in stdlib (#237) 2020-02-25 12:56:51 +01:00
Radosław Rowicki bd7ed2ef8c Instant unification error on arguments count mismatch (#225)
* Instant unification error on arguments count mismatch

* add testcase

* Add newline
2020-02-21 10:28:55 +01:00
Radosław Rowicki 2bf65cfd98 Add Frac (#222)
Fix bugs in Frac

Added optimizer
2020-02-13 11:02:47 +01:00
35 changed files with 3540 additions and 137 deletions
+25 -5
View File
@@ -9,6 +9,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
### 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
### Added
- 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.
- `[a..b]` language construct, returning the list of numbers between
`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.
- 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
@@ -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
pass a (stubbed) contract string.
[Unreleased]: https://github.com/aeternity/aesophia/compare/v4.2.0...HEAD
[4.2.0]: https://github.com/aeternity/aesophia/compare/v4.2.0...v4.1.0
[4.1.0]: https://github.com/aeternity/aesophia/compare/v4.1.0...v4.0.0
[4.0.0]: https://github.com/aeternity/aesophia/compare/v4.0.0...v3.2.0
[Unreleased]: https://github.com/aeternity/aesophia/compare/v4.3.0...HEAD
[4.3.0]: https://github.com/aeternity/aesophia/compare/v4.2.0...v4.3.0
[4.2.0]: https://github.com/aeternity/aesophia/compare/v4.1.0...v4.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.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
+9 -2
View File
@@ -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.
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
[the æternity node](https://github.com/aeternity/epoch). However, it can
also be included in other systems to compile contracts coded in sophia which
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
`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
API changes etc.
## Interface Modules
The basic modules for interfacing the compiler:
+1071
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+183
View 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)
+41 -10
View File
@@ -12,35 +12,66 @@ namespace Func =
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 =
(x) => f(recur(f), x)
/** n-times composition with itself
*/
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 =
if(n == 0) acc
elif(n == 1) 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)
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)
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)
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)
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)
(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)
(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))
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))
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))
+44 -11
View File
@@ -19,10 +19,15 @@ namespace List =
[x] => Some(x)
_::t => last(t)
/** 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)
[] => None
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, [])
private function find_indices_( p : 'a => bool
, l : list('a)
@@ -50,14 +55,22 @@ namespace List =
_::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]
/** 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) = from_to_step_(a, b, s, [])
private function from_to_step_(a, b, s, acc) =
if (a > b) reverse(acc) else from_to_step_(a + s, b, s, a :: 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) =
if(n<0) abort("insert_at underflow") else replace_at_(n, e, l, [])
private function replace_at_(n : int, e : 'a, l : list('a), acc : list('a)) : list('a) =
@@ -66,7 +79,8 @@ namespace List =
h::t => if (n == 0) reverse(e::acc) ++ t
else replace_at_(n-1, e, t, h::acc)
/* 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) =
if(n<0) abort("insert_at underflow") else insert_at_(n, e, l, [])
private function insert_at_(n : int, e : 'a, l : list('a), acc : list('a)) : list('a) =
@@ -75,6 +89,9 @@ namespace List =
[] => abort("insert_at overflow")
h::t => insert_at_(n-1, e, t, h::acc)
/** 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) =
insert_by_(cmp, x, l, [])
private function insert_by_(cmp : (('a, 'a) => bool), x : 'a, l : list('a), acc : list('a)) : list('a) =
@@ -109,6 +126,8 @@ namespace List =
[] => reverse(acc)
h::t => map_(f, t, f(h)::acc)
/** Effectively composition of `map` and `flatten`
*/
function flat_map(f : 'a => list('b), l : list('a)) : list('b) =
ListInternal.flat_map(f, l)
@@ -117,7 +136,8 @@ namespace List =
[] => reverse(acc)
h::t => filter_(p, t, if(p(h)) h::acc else acc)
/* Take `n` first elements */
/** Take `n` first elements
*/
function take(n : int, l : list('a)) : list('a) =
if(n < 0) abort("Take negative number of elements") else take_(n, l, [])
private function take_(n : int, l : list('a), acc : list('a)) : list('a) =
@@ -126,7 +146,8 @@ namespace List =
[] => reverse(acc)
h::t => take_(n-1, t, h::acc)
/* Drop `n` first elements */
/** Drop `n` first elements
*/
function drop(n : int, l : list('a)) : list('a) =
if(n < 0) abort("Drop negative number of elements")
elif (n == 0) l
@@ -134,18 +155,23 @@ namespace List =
[] => []
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) = take_while_(p, l, [])
private function take_while_(p : 'a => bool, l : list('a), acc : list('a)) : list('a) = switch(l)
[] => reverse(acc)
h::t => if(p(h)) take_while_(p, t, h::acc) else reverse(acc)
/* 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)
[] => []
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)) = partition_(p, l, [], [])
private function partition_( p : 'a => bool
, l : list('a)
@@ -155,7 +181,8 @@ namespace List =
[] => (reverse(acc_t), reverse(acc_f))
h::t => if(p(h)) partition_(p, t, h::acc_t, acc_f) else partition_(p, t, acc_t, h::acc_f)
/** Flattens list of lists into a single list
*/
function flatten(ll : list(list('a))) : list('a) = foldr((l1, l2) => l1 ++ l2, [], ll)
function all(p : 'a => bool, l : list('a)) : bool = switch(l)
@@ -171,7 +198,9 @@ namespace List =
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 longer tail.
*/
function zip_with(f : ('a, 'b) => 'c, l1 : list('a), l2 : list('b)) : list('c) = zip_with_(f, l1, l2, [])
private function zip_with_( f : ('a, 'b) => 'c
, l1 : list('a)
@@ -181,7 +210,8 @@ namespace List =
(h1::t1, h2::t2) => zip_with_(f, t1, t2, f(h1, h2)::acc)
_ => reverse(acc)
/* Zips two lists into list of pairs. Drops longer tail. */
/** Zips two lists into list of pairs. Drops longer tail.
*/
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) = unzip_(l, [], [])
@@ -199,7 +229,8 @@ namespace List =
h::t => switch (partition((x) => lesser_cmp(x, h), t))
(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) = intersperse_(delim, l, [])
private function intersperse_(delim : 'a, l : list('a), acc : list('a)) : list('a) = switch(l)
[] => reverse(acc)
@@ -207,6 +238,8 @@ namespace List =
h::t => intersperse_(delim, t, delim::h::acc)
/** Effectively a zip with an infinite sequence of natural numbers
*/
function enumerate(l : list('a)) : list(int * 'a) = enumerate_(l, 0, [])
private function enumerate_(l : list('a), n : int, acc : list(int * 'a)) : list(int * 'a) = switch(l)
[] => reverse(acc)
+20 -2
View File
@@ -10,13 +10,18 @@ namespace Option =
None => false
Some(_) => true
/** Catamorphism on `option`. Also known as inlined pattern matching.
*/
function match(n : 'b, s : 'a => 'b, o : option('a)) : 'b = switch(o)
None => n
Some(x) => s(x)
/** Escape option providing default if `None`
*/
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 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))
_ => None
/** Like `map`, but the function is in `option`
*/
function app_over(f : option ('a => 'b), o : option('a)) : option('b) = switch((f, o))
(Some(ff), Some(xx)) => Some(ff(xx))
_ => None
/** Monadic bind
*/
function flat_map(f : 'a => option('b), o : option('a)) : option('b) = switch(o)
None => None
Some(x) => f(x)
@@ -53,22 +62,31 @@ namespace Option =
None => []
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) = filter_options_(l, [])
private function filter_options_(l : list (option('a)), acc : list('a)) : list('a) = switch(l)
[] => List.reverse(acc)
None::t => filter_options_(t, acc)
Some(x)::t => filter_options_(t, x::acc)
/** 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)) = seq_options_(l, [])
private function seq_options_(l : list (option('a)), acc : list('a)) : option(list('a)) = switch(l)
[] => Some(List.reverse(acc))
None::t => None
Some(x)::t => seq_options_(t, x::acc)
/** Choose `Some` out of two if possible
*/
function choose(o1 : option('a), o2 : option('a)) : option('a) =
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)
[] => None
None::t => choose_first(t)
+6
View File
@@ -6,12 +6,18 @@ namespace Pair =
function snd(t : ('a * 'b)) : 'b = switch(t)
(_, y) => y
/** Map over first
*/
function map1(f : 'a => 'c, t : ('a * 'b)) : ('c * 'b) = switch(t)
(x, y) => (f(x), y)
/** Map over second
*/
function map2(f : 'b => 'c, t : ('a * 'b)) : ('a * 'c) = switch(t)
(x, y) => (x, f(y))
/** Map over both
*/
function bimap(f : 'a => 'c, g : 'b => 'd, t : ('a * 'b)) : ('c * 'd) = switch(t)
(x, y) => (f(x), g(y))
+12
View File
@@ -10,15 +10,23 @@ namespace Triple =
(_, _, z) => z
/** Map over first
*/
function map1(f : 'a => 'm, t : ('a * 'b * 'c)) : ('m * 'b * 'c) = switch(t)
(x, y, z) => (f(x), y, z)
/** Map over second
*/
function map2(f : 'b => 'm, t : ('a * 'b * 'c)) : ('a * 'm * 'c) = switch(t)
(x, y, z) => (x, f(y), z)
/** Map over third
*/
function map3(f : 'c => 'm, t : ('a * 'b * 'c)) : ('a * 'b * 'm) = switch(t)
(x, y, z) => (x, y, f(z))
/** Map over all elements
*/
function trimap( f : 'a => 'x
, g : 'b => 'y
, h : 'c => 'z
@@ -29,9 +37,13 @@ namespace Triple =
function swap(t : ('a * 'b * 'c)) : ('c * 'b * 'a) = switch(t)
(x, y, z) => (z, y, x)
/** Right rotation
*/
function rotr(t : ('a * 'b * 'c)) : ('c * 'a * 'b) = switch(t)
(x, y, z) => (z, x, y)
/** Left rotation
*/
function rotl(t : ('a * 'b * 'c)) : ('b * 'c * 'a) = switch(t)
(x, y, z) => (y, z, x)
+1 -1
View File
@@ -15,7 +15,7 @@
{base_plt_apps, [erts, kernel, stdlib, crypto, mnesia]}
]}.
{relx, [{release, {aesophia, "4.2.0"},
{relx, [{release, {aesophia, "4.3.0"},
[aesophia, aebytecode, getopt]},
{dev_mode, true},
+2
View File
@@ -194,6 +194,8 @@ encode_expr({bytes, _, B}) ->
encode_expr({Lit, _, L}) when Lit == oracle_pubkey; Lit == oracle_query_id;
Lit == contract_pubkey; Lit == account_pubkey ->
aeser_api_encoder:encode(Lit, L);
encode_expr({app, _, {'-', _}, [{int, _, N}]}) ->
encode_expr({int, [], -N});
encode_expr({app, _, F, As}) ->
Ef = encode_expr(F),
Eas = encode_exprs(As),
+38 -15
View File
@@ -12,7 +12,11 @@
-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()}
| {app_t, aeso_syntax:ann(), utype(), [utype()]}
@@ -2072,7 +2076,8 @@ unify1(_Env, {qcon, _, Name}, {qcon, _, Name}, _When) ->
true;
unify1(_Env, {bytes_t, _, Len}, {bytes_t, _, Len}, _When) ->
true;
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, Args1, Args2, When) andalso unify(Env, Result1, Result2, When);
unify1(Env, {app_t, _, {Tag, _, F}, Args1}, {app_t, _, {Tag, _, F}, Args2}, When)
@@ -2261,6 +2266,24 @@ mk_t_err(Pos, Msg) ->
mk_t_err(Pos, Msg, 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}) ->
Msg = io_lib:format("Cannot unify ~s\n and ~s\n",
[pp(instantiate(A)), pp(instantiate(B))]),
@@ -2343,14 +2366,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",
[pp_type("", Type), pp_loc(Type), pp_type("", Type1)]),
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}) ->
Msg = io_lib:format("The event constructor ~s (at ~s) has too many indexed values (max 3)\n",
[name(Constr), pp_loc(Constr)]),
@@ -2394,13 +2409,21 @@ mk_error({include, _, {string, Pos, Name}}) ->
[binary_to_list(Name), pp_loc(Pos)]),
mk_t_err(pos(Pos), Msg);
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)]),
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}) ->
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)]),
-1
View File
@@ -291,7 +291,6 @@ decls_to_fcode(Env, Decls) ->
end, Env1, Decls).
-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, _}) ->
case is_no_code(Env) of
false -> fcode_error({missing_definition, Id});
+5 -3
View File
@@ -38,6 +38,7 @@
| pp_assembler
| pp_bytecode
| no_code
| keep_included
| {backend, aevm | fate}
| {include, {file_system, [string()]} |
{explicit_files, #{string() => binary()}}}
@@ -336,12 +337,12 @@ to_sophia_value(ContractString, FunName, ok, Data, Options0) ->
try
{ok, aeso_vm_decode:from_fate(Type, aeb_fate_encoding:deserialize(Data))}
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",
[aeb_fate_encoding:deserialize(Data), Type1]),
{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]),
{error, [aeso_errors:new(data_error, Msg)]}
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) ->
{ok, Ast} = aeso_parser:type(String),
Ast = aeso_parser:run_parser(aeso_parser:type(), String),
try aeso_ast_to_icode:ast_typerep(Ast) of
Type -> {ok, Type}
catch _:_ -> {error, bad_type}
+40 -20
View File
@@ -3,20 +3,33 @@
%%% Description :
%%% Created : 1 Mar 2018 by Ulf Norell
-module(aeso_parser).
-compile({no_auto_import,[map_get/2]}).
-export([string/1,
string/2,
string/3,
auto_imports/1,
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").
-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()}.
escape_errors({ok, Ok}) ->
Ok;
escape_errors({error, Err}) ->
parse_error(Err).
-spec string(string()) -> parse_result().
string(String) ->
string(String, sets:new(), []).
@@ -30,21 +43,17 @@ string(String, Opts) ->
-spec string(string(), sets:set(include_hash()), aeso_compiler:options()) -> parse_result().
string(String, Included, Opts) ->
case parse_and_scan(file(), String, Opts) of
{ok, AST} ->
case expand_includes(AST, Included, Opts) of
{ok, AST1} -> AST1;
{error, Err} -> parse_error(Err)
end;
{error, Err} ->
parse_error(Err)
AST = run_parser(file(), String, Opts),
case expand_includes(AST, Included, Opts) of
{ok, AST1} -> AST1;
{error, Err} -> parse_error(Err)
end.
type(String) ->
case parse_and_scan(type(), String, []) of
{ok, AST} -> {ok, AST};
{error, Err} -> {error, [mk_error(Err)]}
end.
run_parser(P, Inp) ->
escape_errors(parse_and_scan(P, Inp, [])).
run_parser(P, Inp, Opts) ->
escape_errors(parse_and_scan(P, Inp, Opts)).
parse_and_scan(P, S, Opts) ->
set_current_file(proplists:get_value(src_file, Opts, no_file)),
@@ -102,7 +111,7 @@ decl() ->
%% Function declarations
, ?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]) ->
@@ -596,8 +605,13 @@ expand_includes(AST, Included, Opts) ->
|| File <- lists:usort(auto_imports(AST)) ] ++ AST,
expand_includes(AST1, Included, [], Opts).
expand_includes([], _Included, Acc, _Opts) ->
{ok, lists:reverse(Acc)};
expand_includes([], Included, Acc, Opts) ->
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) ->
case get_include_code(File, Ann, Opts) of
{ok, Code} ->
@@ -656,8 +670,14 @@ stdlib_options() ->
get_include_code(File, Ann, Opts) ->
case {read_file(File, Opts), read_file(File, stdlib_options())} of
{{ok, _}, {ok,_ }} ->
fail(ann_pos(Ann), "Illegal redefinition of standard library " ++ File);
{{ok, Bin}, {ok, _}} ->
case filename:basename(File) == File of
true -> { error
, fail( ann_pos(Ann)
, "Illegal redefinition of standard library " ++ binary_to_list(File))};
%% If a path is provided then the stdlib takes lower priority
false -> {ok, binary_to_list(Bin)}
end;
{_, {ok, Bin}} ->
{ok, binary_to_list(Bin)};
{{ok, Bin}, _} ->
+13 -8
View File
@@ -145,8 +145,12 @@ decl(D, Options) ->
with_options(Options, fun() -> decl(D) end).
-spec decl(aeso_syntax:decl()) -> doc().
decl({contract, _, C, Ds}) ->
block(follow(text("contract"), hsep(name(C), text("="))), decls(Ds));
decl({contract, Attrs, C, 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}) ->
block(follow(text("namespace"), hsep(name(C), text("="))), decls(Ds));
decl({pragma, _, Pragma}) -> pragma(Pragma);
@@ -155,13 +159,16 @@ decl({type_def, _, T, Vars, Def}) ->
Kind = element(1, Def),
equals(typedecl(Kind, T, Vars), typedef(Def));
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
true -> text("entrypoint");
false -> text("function")
end,
hsep(Fun, typed(name(F), T));
hsep(lists:map(Mod, Ann) ++ [Fun, typed(name(F), T)]);
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));
(_) -> empty() end,
Fun = case aeso_syntax:get_ann(entrypoint, Attrs, false) of
@@ -364,7 +371,8 @@ expr_p(_, {Type, _, Bin})
Type == oracle_query_id ->
text(binary_to_list(aeser_api_encoder:encode(Type, Bin)));
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}) ->
case C of
$' -> text("'\\''");
@@ -486,6 +494,3 @@ get_elifs(If = {'if', Ann, Cond, Then, Else}, Elifs) ->
end;
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]).
+8 -4
View File
@@ -37,20 +37,24 @@
-type decl() :: {contract, ann(), con(), [decl()]}
| {namespace, ann(), con(), [decl()]}
| {pragma, ann(), pragma()}
| {type_decl, ann(), id(), [tvar()]}
| {type_decl, ann(), id(), [tvar()]} % Only for error msgs
| {type_def, ann(), id(), [tvar()], typedef()}
| {fun_decl, ann(), id(), type()}
| {fun_clauses, ann(), id(), type(), [letbind()]}
| {block, ann(), [decl()]}
| letbind().
| letfun()
| letval(). % Only for error msgs
-type compiler_version() :: [non_neg_integer()].
-type pragma() :: {compiler, '==' | '<' | '>' | '=<' | '>=', compiler_version()}.
-type letval() :: {letval, ann(), pat(), expr()}.
-type letfun() :: {letfun, ann(), id(), [pat()], type(), expr()}.
-type letbind()
:: {letval, ann(), pat(), expr()}
| {letfun, ann(), id(), [pat()], type(), expr()}.
:: letfun()
| letval().
-type arg() :: {arg, ann(), id(), type()}.
-1
View File
@@ -45,7 +45,6 @@ fold(Alg = #alg{zero = Zero, plus = Plus, scoped = Scoped}, Fun, K, X) ->
%% decl()
{contract, _, _, Ds} -> Decl(Ds);
{namespace, _, _, Ds} -> Decl(Ds);
{type_decl, _, I, _} -> BindType(I);
{type_def, _, I, _, D} -> Plus(BindType(I), Decl(D));
{fun_decl, _, _, T} -> Type(T);
{letval, _, P, E} -> Scoped(BindExpr(P), Expr(E));
+1 -1
View File
@@ -1,6 +1,6 @@
{application, aesophia,
[{description, "Contract Language for aeternity"},
{vsn, "4.2.0"},
{vsn, "4.3.0"},
{registered, []},
{applications,
[kernel,
+69 -5
View File
@@ -375,11 +375,15 @@ failing_contracts() ->
" r.foo : (gas : int, value : int) => Remote.themap\n"
"against the expected type\n"
" (gas : int, value : int) => map(string, int)">>])
, ?TYPE_ERROR(bad_include_and_ns,
[<<?Pos(2, 11)
"Include of 'included.aes' at line 2, column 11\nnot allowed, include only allowed at top level.">>,
<<?Pos(3, 13)
"Nested namespace not allowed\nNamespace 'Foo' at line 3, column 13 not defined at top level.">>])
, ?TYPE_ERROR(not_toplevel_include,
[<<?Pos(2, 11)
"Include of 'included.aes' at line 2, column 11\nnot allowed, include only allowed at top level.">>])
, ?TYPE_ERROR(not_toplevel_namespace,
[<<?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,
[<<?Pos(11, 5)
"Cannot unify address\n"
@@ -612,6 +616,44 @@ failing_contracts() ->
[<<?Pos(5, 28)
"Invalid call to contract entrypoint 'Foo.foo'.\n"
"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,
[<<?Pos(3, 16)
"Mixed record fields and map keys in\n"
@@ -623,6 +665,28 @@ failing_contracts() ->
"Empty record/map update\n"
" r {}">>
])
, ?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).
+1 -2
View File
@@ -58,8 +58,7 @@ contract Greeter =
let state = { greeting = "Hello" }
let setGreeting =
(greeting: string) =>
function setGreeting(greeting: string) =
state{ greeting = greeting }
+63 -29
View File
@@ -1,44 +1,78 @@
// 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-
* line
* comment
*/
function foo : _
stateful function foo : _
entrypoint bar : int => (int * 'a)
contract AllSyntax =
type typeDecl = int
type paramTypeDecl('a, 'b) = (('a, 'b) => 'b) => list('a) => 'b => 'b
datatype mickiewicz = Adam | Mickiewicz
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 }
record recordType = { z : nestedRecord, y : int }
datatype variantType('a) = None | Some('a)
type state = shakespeare(int)
let valWithType : map(int, int) => option(int) = (m) => Map.get(m, 42)
let valNoType =
if(valWithType(Map.empty) == None)
print(42 mod 10 * 5 / 3)
entrypoint init() = {
johann = 1000,
wolfgang = -10,
von = (2 + 2, 0, List.sum([x | k <- [1,2,3]
, let l = k + 1
, if(l < 10)
, let f(x) = x + 100
, Adam <- [Adam, Mickiewicz]
, let x = f(l)
])),
goethe = () }
function funWithType(x : int, y) : int * list(int) = (x, 0 :: [y] ++ [])
function funNoType() =
let foo = (x, y : bool) =>
if (! (y && x =< 0x0b || true)) [x]
else [11..20]
let setY(r : recordType) : unit = r{ y = 5 }
let setX(r : recordType, x : int) : recordType = r { z.x = x } // nested record update
let getY(r) = switch(r) {y = y} => y
switch (funWithType(1, -2))
(x, [y, z]) => bar({x = z, y = -y + - -z * (-1)})
(x, y :: _) => ()
function f() =
let kp = "nietzsche"
let p = "Пушкин"
let k(x : bytes(8)) : bytes(8) = Bytes.to_int(#fedcba9876543210)
let hash : address = #01ab0fff11
let b = false
let qcon = Mod.Con
let str = "blabla\nfoo"
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
View File
@@ -0,0 +1,4 @@
contract C =
type id('a) = 'a
entrypoint f() : id = 123
entrypoint g() : id(int, int) = 123
+6
View 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")
@@ -0,0 +1,5 @@
contract C =
entrypoint f() =
let z = 123
{}{ [1 = 0] = z + 1 }
2
+3
View File
@@ -0,0 +1,3 @@
contract C =
type t
entrypoint f() = 123
+3
View File
@@ -0,0 +1,3 @@
contract IWantToBelieve =
type stateT('s, 'm, 'a) = 's => 'm('a * 's)
entrypoint s() = 123
+2 -2
View File
@@ -15,7 +15,7 @@ contract MultiSig =
| OwnerRemoved (address) // of { .removedOwner : Address }
| ReqChanged (int) // of { .newReq : int }
let maxOwners : int = 250
function maxOwners() : int = 250
record state = { nRequired : int
, nOwners : int
@@ -68,7 +68,7 @@ contract MultiSig =
switch(check_pending(callhash()))
CheckFail(state') => { state = state' }
CheckOk(state') =>
if(state.nOwners >= maxOwners) () /* TODO */
if(state.nOwners >= maxOwners()) () /* TODO */
else
let nOwners' = state'.nOwners + 1
{ state = state' { owners = Map.insert(nOwners', newOwner, state'.owners)
@@ -0,0 +1,5 @@
contract C1 =
entrypoint f : int
contract C =
entrypoint f() = 123
+6
View File
@@ -0,0 +1,6 @@
namespace BadNs =
contract Con =
entrypoint e : () => int
contract Con =
entrypoint foo() = 43
+5
View File
@@ -0,0 +1,5 @@
namespace BadNs =
include "included.aes"
contract Con =
entrypoint foo() = 43
@@ -1,5 +1,4 @@
contract Bad =
include "included.aes"
contract BadCon =
namespace Foo =
function foo() = 42
+3
View File
@@ -0,0 +1,3 @@
contract C =
let this_is_illegal = 2/0
entrypoint this_is_legal() = 2/0
-13
View File
@@ -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 =
// Types