Compare commits

..

11 Commits

Author SHA1 Message Date
Hans Svensson fd6cde535e Merge pull request #296 from davidyuk/patch-3
docs: Use consistent event definitions between examples
2021-06-24 09:30:08 +02:00
Hans Svensson b25339bb8f Merge pull request #303 from aeternity/radrow-patch-1
Mention `init` quirk with Call.value
2021-04-29 18:51:13 +02:00
Hans Svensson cf793667ca Merge pull request #304 from aeternity/clarify-aesocompiler
Clarify aeso_compiler use
2021-04-29 18:50:32 +02:00
Artur Puzio c54a0cec3d Clarify aeso_compiler use 2021-03-24 10:34:39 +00:00
Radosław Rowicki bc47c25138 Mention init quirk with Call.value 2021-03-22 10:26:34 +01:00
Radosław Rowicki 3b2ce63fa7 Merge pull request #300 from aeternity/erlps-lima
Trampoline in parser
2021-03-08 13:33:34 +01:00
radrow 8b4a1aaf0d Trampoline 2021-03-08 12:45:21 +01:00
Radosław Rowicki c6e7db2381 Merge pull request #299 from aeternity/fix-ets
Fix constraints ordering
2021-03-05 10:42:16 +01:00
Radosław Rowicki b8002029cf Merge pull request #294 from aeternity/mergesort
Upgrade sorting function
2021-02-23 08:58:36 +01:00
Denis Davidyuk 4630f8a09b Use consistent event definitions between examples 2021-02-16 14:52:37 +03:00
radrow 1a14602f36 Upgrade sorting function 2021-02-09 14:18:42 +01:00
5 changed files with 92 additions and 17 deletions
+2 -2
View File
@@ -686,8 +686,8 @@ will emit one Event of each kind in the example.
``` ```
entrypoint emit_events() : () = entrypoint emit_events() : () =
Chain.event(TheFirstEvent(42)) Chain.event(Event1(42, 34, "foo"))
Chain.event(AnotherEvent(Contract.address, "This is not indexed")) Chain.event(Event2("This is not indexed", Contract.address))
``` ```
#### Argument order #### Argument order
+13 -2
View File
@@ -569,12 +569,15 @@ Call.caller : address
The address of the entity (possibly another contract) calling the contract. The address of the entity (possibly another contract) calling the contract.
### value ### value
``` ```
Call.value : int Call.value : int
``` ```
The amount of coins transferred to the contract in the call. The amount of coins transferred to the contract in the call. Note that in the `init`
entrypoint this value will be always `0` in order to get the contract creation value
one needs to inspect `Contract.balance`.
### gas ### gas
@@ -975,12 +978,20 @@ List.unzip(l : list('a * 'b)) : list('a) * list('b)
Opposite to the `zip` operation. Takes a list of pairs and returns pair of lists with respective elements on same indices. Opposite to the `zip` operation. Takes a list of pairs and returns pair of lists with respective elements on same indices.
### merge
```
List.merge(lesser_cmp : ('a, 'a) => bool, l1 : list('a), l2 : list('a)) : list('a)
```
Merges two sorted lists into a single sorted list. O(length(l1) + length(l2))
### sort ### sort
``` ```
List.sort(lesser_cmp : ('a, 'a) => bool, l : list('a)) : list('a) List.sort(lesser_cmp : ('a, 'a) => bool, l : list('a)) : list('a)
``` ```
Sorts a list using given comparator. `lesser_cmp(x, y)` should return `true` iff `x < y`. If `lesser_cmp` is not transitive or there exists an element `x` such that `lesser_cmp(x, x)` or there exists a pair of elements `x` and `y` such that `lesser_cmp(x, y) && lesser_cmp(y, x)` then the result is undefined. Currently O(n^2). Sorts a list using given comparator. `lesser_cmp(x, y)` should return `true` iff `x < y`. If `lesser_cmp` is not transitive or there exists an element `x` such that `lesser_cmp(x, x)` or there exists a pair of elements `x` and `y` such that `lesser_cmp(x, y) && lesser_cmp(y, x)` then the result is undefined. O(length(l) * log_2(length(l))).
### intersperse ### intersperse
+61 -5
View File
@@ -227,11 +227,67 @@ namespace List =
(left, right)::t => unzip_(t, left::acc_l, right::acc_r) (left, right)::t => unzip_(t, left::acc_l, right::acc_r)
// TODO: Improve? /** Merges two sorted lists using `lt` comparator
function sort(lesser_cmp : ('a, 'a) => bool, l : list('a)) : list('a) = switch(l) */
[] => [] function
h::t => switch (partition((x) => lesser_cmp(x, h), t)) merge : (('a, 'a) => bool, list('a), list('a)) => list('a)
(lesser, bigger) => sort(lesser_cmp, lesser) ++ h::sort(lesser_cmp, bigger) merge(lt, x::xs, y::ys) =
if(lt(x, y)) x::merge(lt, xs, y::ys)
else y::merge(lt, x::xs, ys)
merge(_, [], ys) = ys
merge(_, xs, []) = xs
/** Mergesort inspired by
* https://hackage.haskell.org/package/base-4.14.1.0/docs/src/Data.OldList.html#sort
*/
function
sort : (('a, 'a) => bool, list('a)) => list('a)
sort(_, []) = []
sort(lt, l) =
merge_all(lt, monotonic_subs(lt, l))
/** Splits list into compound increasing sublists
*/
private function
monotonic_subs : (('a, 'a) => bool, list('a)) => list(list('a))
monotonic_subs(lt, x::y::rest) =
if(lt(y, x)) desc(lt, y, [x], rest)
else asc(lt, y, [x], rest)
monotonic_subs(_, l) = [l]
/** Extracts the longest descending prefix and proceeds with monotonic split
*/
private function
desc : (('a, 'a) => bool, 'a, list('a), list('a)) => list(list('a))
desc(lt, x, acc, h::t) =
if(lt(x, h)) (x::acc) :: monotonic_subs(lt, h::t)
else desc(lt, h, x::acc, t)
desc(_, x, acc, []) = [x::acc]
/** Extracts the longest ascending prefix and proceeds with monotonic split
*/
private function
asc : (('a, 'a) => bool, 'a, list('a), list('a)) => list(list('a))
asc(lt, x, acc, h::t) =
if(lt(h, x)) List.reverse(x::acc) :: monotonic_subs(lt, h::t)
else asc(lt, h, x::acc, t)
asc(_, x, acc, []) = [List.reverse(x::acc)]
/** Merges list of sorted lists
*/
private function
merge_all : (('a, 'a) => bool, list(list('a))) => list('a)
merge_all(_, [part]) = part
merge_all(lt, parts) = merge_all(lt, merge_pairs(lt, parts))
/** Single round of `merge_all` pairs of lists in a list of list
*/
private function
merge_pairs : (('a, 'a) => bool, list(list('a))) => list(list('a))
merge_pairs(lt, x::y::rest) = merge(lt, x, y) :: merge_pairs(lt, rest)
merge_pairs(_, l) = l
/** Puts `delim` between every two members of the list /** Puts `delim` between every two members of the list
*/ */
+1 -1
View File
@@ -2,7 +2,7 @@
%%% @author Happi (Erik Stenman) %%% @author Happi (Erik Stenman)
%%% @copyright (C) 2017, Aeternity Anstalt %%% @copyright (C) 2017, Aeternity Anstalt
%%% @doc %%% @doc
%%% Compiler from Aeterinty Sophia language to the Aeternity VM, aevm. %%% Compiler from Aeterinty Sophia language to both AEVM and FATE VM.
%%% @end %%% @end
%%% Created : 12 Dec 2017 %%% Created : 12 Dec 2017
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
+15 -7
View File
@@ -74,25 +74,31 @@
%% first argument. I.e. no backtracking to the second argument if the first %% first argument. I.e. no backtracking to the second argument if the first
%% fails. %% fails.
trampoline({bounce, Cont}) when is_function(Cont, 0) ->
trampoline(Cont());
trampoline(Res) ->
Res.
-define(BOUNCE(X), {bounce, fun() -> X end}).
%% Apply a parser to its continuation. This compiles a parser to its low-level representation. %% Apply a parser to its continuation. This compiles a parser to its low-level representation.
-spec apply_p(parser(A), fun((A) -> parser1(B))) -> parser1(B). -spec apply_p(parser(A), fun((A) -> parser1(B))) -> parser1(B).
apply_p(?lazy(F), K) -> apply_p(F(), K); apply_p(?lazy(F), K) -> apply_p(F(), K);
apply_p(?fail(Err), _) -> {fail, Err}; apply_p(?fail(Err), _) -> {fail, Err};
apply_p(?choice([P | Ps]), K) -> lists:foldl(fun(Q, R) -> choice1(apply_p(Q, K), R) end, apply_p(?choice([P | Ps]), K) -> lists:foldl(fun(Q, R) -> choice1(trampoline(apply_p(Q, K)), R) end,
apply_p(P, K), Ps); trampoline(apply_p(P, K)), Ps);
apply_p(?bind(P, F), K) -> apply_p(P, fun(X) -> apply_p(F(X), K) end); apply_p(?bind(P, F), K) -> apply_p(P, fun(X) -> apply_p(F(X), K) end);
apply_p(?right(P, Q), K) -> apply_p(P, fun(_) -> apply_p(Q, K) end); apply_p(?right(P, Q), K) -> apply_p(P, fun(_) -> apply_p(Q, K) end);
apply_p(?left(P, Q), K) -> apply_p(P, fun(X) -> apply_p(Q, fun(_) -> K(X) end) end); apply_p(?left(P, Q), K) -> apply_p(P, fun(X) -> apply_p(Q, fun(_) -> K(X) end) end);
apply_p(?map(F, P), K) -> apply_p(P, fun(X) -> K(F(X)) end); apply_p(?map(F, P), K) -> apply_p(P, fun(X) -> K(F(X)) end);
apply_p(?layout, K) -> {layout, K, {fail, {expected, layout_block}}}; apply_p(?layout, K) -> {layout, K, {fail, {expected, layout_block}}};
apply_p(?tok(Atom), K) -> {tok_bind, #{Atom => K}}; apply_p(?tok(Atom), K) -> {tok_bind, #{Atom => K}};
apply_p(?return(X), K) -> K(X); apply_p(?return(X), K) -> ?BOUNCE(K(X));
apply_p([P | Q], K) -> apply_p(P, fun(H) -> apply_p(Q, fun(T) -> K([H | T]) end) end); apply_p([P | Q], K) -> apply_p(P, fun(H) -> apply_p(Q, fun(T) -> K([H | T]) end) end);
apply_p(T, K) when is_tuple(T) -> apply_p(tuple_to_list(T), fun(Xs) -> K(list_to_tuple(Xs)) end); apply_p(T, K) when is_tuple(T) -> apply_p(tuple_to_list(T), fun(Xs) -> K(list_to_tuple(Xs)) end);
apply_p(M, K) when is_map(M) -> apply_p(M, K) when is_map(M) ->
{Keys, Ps} = lists:unzip(maps:to_list(M)), {Keys, Ps} = lists:unzip(maps:to_list(M)),
apply_p(Ps, fun(Vals) -> K(maps:from_list(lists:zip(Keys, Vals))) end); apply_p(Ps, fun(Vals) -> K(maps:from_list(lists:zip(Keys, Vals))) end);
apply_p(X, K) -> K(X). apply_p(X, K) -> ?BOUNCE(K(X)).
%% -- Primitive combinators -------------------------------------------------- %% -- Primitive combinators --------------------------------------------------
@@ -160,7 +166,7 @@ layout() -> ?layout.
%% @doc Parse a sequence of tokens using a parser. Fails if the parse is ambiguous. %% @doc Parse a sequence of tokens using a parser. Fails if the parse is ambiguous.
-spec parse(parser(A), tokens()) -> {ok, A} | {error, term()}. -spec parse(parser(A), tokens()) -> {ok, A} | {error, term()}.
parse(P, S) -> parse(P, S) ->
case parse1(apply_p(P, fun(X) -> {return_plus, X, {fail, no_error}} end), S) of case parse1(trampoline(apply_p(P, fun(X) -> {return_plus, X, {fail, no_error}} end)), S) of
{[], {Pos, Err}} -> {error, {add_current_file(Pos), parse_error, flatten_error(Err)}}; {[], {Pos, Err}} -> {error, {add_current_file(Pos), parse_error, flatten_error(Err)}};
{[A], _} -> {ok, A}; {[A], _} -> {ok, A};
{As, _} -> {error, {{1, 1}, ambiguous_parse, As}} {As, _} -> {error, {{1, 1}, ambiguous_parse, As}}
@@ -241,7 +247,7 @@ col(T) when is_tuple(T) -> element(2, pos(T)).
%% If both parsers want the next token we grab it and merge the continuations. %% If both parsers want the next token we grab it and merge the continuations.
choice1({tok_bind, Map1}, {tok_bind, Map2}) -> choice1({tok_bind, Map1}, {tok_bind, Map2}) ->
{tok_bind, merge_with(fun(F, G) -> fun(T) -> choice1(F(T), G(T)) end end, Map1, Map2)}; {tok_bind, merge_with(fun(F, G) -> fun(T) -> choice1(trampoline(F(T)), trampoline(G(T))) end end, Map1, Map2)};
%% If both parsers fail we combine the error messages. If only one fails we discard it. %% If both parsers fail we combine the error messages. If only one fails we discard it.
choice1({fail, E1}, {fail, E2}) -> {fail, add_error(E1, E2)}; choice1({fail, E1}, {fail, E2}) -> {fail, add_error(E1, E2)};
@@ -255,7 +261,7 @@ choice1(P, {return_plus, X, Q}) -> {return_plus, X, choice1(P, Q)};
%% If both sides want a layout block we combine them. If only one side wants a layout block we %% If both sides want a layout block we combine them. If only one side wants a layout block we
%% will commit to a layout block is there is one. %% will commit to a layout block is there is one.
choice1({layout, F, P}, {layout, G, Q}) -> choice1({layout, F, P}, {layout, G, Q}) ->
{layout, fun(N) -> choice1(F(N), G(N)) end, choice1(P, Q)}; {layout, fun(N) -> choice1(trampoline(F(N)), trampoline(G(N))) end, choice1(P, Q)};
choice1({layout, F, P}, Q) -> {layout, F, choice1(P, Q)}; choice1({layout, F, P}, Q) -> {layout, F, choice1(P, Q)};
choice1(P, {layout, G, Q}) -> {layout, G, choice1(P, Q)}. choice1(P, {layout, G, Q}) -> {layout, G, choice1(P, Q)}.
@@ -278,6 +284,8 @@ parse1(P, S) ->
%% The main work horse. Returns a list of possible parses and an error message in case parsing %% The main work horse. Returns a list of possible parses and an error message in case parsing
%% fails. %% fails.
-spec parse1(parser1(A), #ts{}, [A], term()) -> {[A], error()}. -spec parse1(parser1(A), #ts{}, [A], term()) -> {[A], error()}.
parse1({bounce, F}, Ts, Acc, Err) ->
parse1(F(), Ts, Acc, Err);
parse1({tok_bind, Map}, Ts, Acc, Err) -> parse1({tok_bind, Map}, Ts, Acc, Err) ->
case next_token(Ts) of case next_token(Ts) of
{T, Ts1} -> {T, Ts1} ->