Compare commits

..

33 Commits

Author SHA1 Message Date
sennui 451b3636ac change aebytecode ver to the one from full node with my changes on top 2019-08-14 15:22:30 +02:00
sennui 514d80259e add extra argument to claim for bidding 2019-08-14 15:20:09 +02:00
Thomas Arts df12f6af91 Merge pull request #118 from aeternity/PT-167126818
Pt 167126818
2019-08-06 15:30:47 +02:00
Thomas Arts 6aed5dfacb Upgrade to newer aebytecode version 2019-08-06 13:20:03 +02:00
Thomas Arts cecc977898 Compiler returns abi_version 2019-08-06 13:11:31 +02:00
Ulf Norell 74933b0616 Merge pull request #117 from aeternity/PT-167701356-split-store
PT-167701356 split store
2019-08-06 12:27:18 +02:00
Hans Svensson 6a27c4a68b Merge pull request #116 from aeternity/another_no_code
to_sophia_value should also use no_code option
2019-08-05 15:21:27 +02:00
Hans Svensson d526e55c26 to_sophia_value should also use no_code option 2019-08-05 15:19:22 +02:00
Hans Svensson 6f7f5fa13c Merge pull request #115 from aeternity/PT-166731397-add_compiler_backend
PT-166731397 Add compiler backend
2019-08-05 15:00:32 +02:00
Ulf Norell 2d6381dc6f Generate INIT function which writes the state instead of returning it 2019-08-05 14:36:59 +02:00
Hans Svensson 3663b4e5d0 Add no_code option to aeso_compile (for encode/decode calldata) 2019-08-05 14:33:53 +02:00
Hans Svensson 4478fee6e6 Add ACI calldata test 2019-08-05 14:33:53 +02:00
Ulf Norell 79ae92a068 Add missing error message 2019-08-05 14:01:35 +02:00
Ulf Norell eb968d3cb9 Merge pull request #114 from aeternity/latest-aebytecode
Update to latest aebytecode
2019-08-05 11:54:01 +02:00
Ulf Norell 054a5a4867 Update to latest aebytecode 2019-08-05 11:51:10 +02:00
Ulf Norell e198dd8311 Merge pull request #113 from aeternity/test-fixes
Update test case
2019-08-05 09:31:31 +02:00
Ulf Norell 46a996ead8 Update test case 2019-08-05 09:20:09 +02:00
Hans Svensson 2bf6ab7655 Merge pull request #110 from radrow/patch-1
Covered qid case in ast_typerep
2019-08-05 09:15:12 +02:00
Ulf Norell 5ff7aa5821 Merge pull request #109 from radrow/tuple-type
Change tuple typing syntax
2019-08-05 09:13:30 +02:00
Radosław Rowicki 045df292be Fixed pretty printing and pattern split (#111) 2019-07-29 14:27:01 +03:00
Radosław Rowicki c97eb99921 Fixed double parens in ACI pp
Co-Authored-By: Ulf Norell <ulf.norell@gmail.com>
2019-07-29 11:01:38 +02:00
Radosław Rowicki 4c78ab3aee Covered qid case in ast_typerep
Because `qid` was not accepted the following code 

```
contract Test = 
   datatype myOption('a) = MyNone | MySome('a)
   entrypoint optionFn(v: myOption(string)): myOption(string) = v
```
Used to lead to `function_clause` error.

Bug copyright (c) @nduchak
2019-07-26 15:31:06 +02:00
radrow 5ff983b0b3 Updated tests 2019-07-22 13:56:45 +02:00
Hans Svensson 4bf382a997 Merge pull request #107 from radrow/master
Changed 'require' function return type to Unit
2019-07-20 21:05:40 +02:00
radrow 4c72045a86 Changed tuple type parsing rule 2019-07-20 19:00:53 +02:00
radrow 7daf218b2a Changed 'require' function return type to Unit 2019-07-19 18:10:54 +02:00
radrow 973850e6a6 Fix pat split 2019-07-11 18:28:50 +02:00
Tobias Lindahl 19948c6aad Merge pull request #104 from aeternity/PT-166868668-decode-fate-revert
Properly decode revert strings for fate as well
2019-07-09 16:52:35 +02:00
Tobias Lindahl c4660fe0cf Properly decode revert strings for fate as well 2019-07-09 16:24:56 +02:00
Tobias Lindahl e326908623 Merge pull request #103 from aeternity/PT-166868668-fate-abort
Use EXIT for internal errors to burn all gas
2019-07-09 15:47:46 +02:00
Tobias Lindahl 9be528a579 Use EXIT for internal errors to burn all gas 2019-07-09 14:36:09 +02:00
Tobias Lindahl f67d7354a2 Merge pull request #102 from aeternity/PT-166927306-names-as-strings
Use a name string rather than a name hash in transfer and revoke
2019-07-01 10:55:38 +02:00
Tobias Lindahl 6f873e45b8 Use a name string rather than a name hash in transfer and revoke 2019-07-01 07:42:08 +02:00
35 changed files with 271 additions and 131 deletions
+2
View File
@@ -19,3 +19,5 @@ rebar3.crashdump
*.erl~ *.erl~
*.aes~ *.aes~
aesophia aesophia
.qcci
current_counterexample.eqc
+1 -1
View File
@@ -2,7 +2,7 @@
{erl_opts, [debug_info]}. {erl_opts, [debug_info]}.
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {ref,"c63ac88"}}} {deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {ref,"adf3664"}}}
, {getopt, "1.0.1"} , {getopt, "1.0.1"}
, {eblake2, "1.0.0"} , {eblake2, "1.0.0"}
, {jsx, {git, "https://github.com/talentdeficit/jsx.git", , {jsx, {git, "https://github.com/talentdeficit/jsx.git",
+1 -1
View File
@@ -1,7 +1,7 @@
{"1.1.0", {"1.1.0",
[{<<"aebytecode">>, [{<<"aebytecode">>,
{git,"https://github.com/aeternity/aebytecode.git", {git,"https://github.com/aeternity/aebytecode.git",
{ref,"c63ac888dd71c305cbc6d4f70953a176bf1f78f7"}}, {ref,"adf3664dd03626c115756f79fa0e602fda24318d"}},
0}, 0},
{<<"aeserialization">>, {<<"aeserialization">>,
{git,"https://github.com/aeternity/aeserialization.git", {git,"https://github.com/aeternity/aeserialization.git",
+4 -1
View File
@@ -264,7 +264,10 @@ decode_types(Ets) ->
decode_type(#{tuple := Ets}) -> decode_type(#{tuple := Ets}) ->
Ts = decode_types(Ets), Ts = decode_types(Ets),
[$(,lists:join(",", Ts),$)]; case Ts of
[] -> ["unit"];
_ -> [$(,lists:join(" * ", Ts),$)]
end;
decode_type(#{record := Efs}) -> decode_type(#{record := Efs}) ->
Fs = decode_fields(Efs), Fs = decode_fields(Efs),
[${,lists:join(",", Fs),$}]; [${,lists:join(",", Fs),$}];
+11 -6
View File
@@ -156,7 +156,7 @@ bind_tvars(Xs, Env) ->
check_tvar(#env{ typevars = TVars}, T = {tvar, _, X}) -> check_tvar(#env{ typevars = TVars}, T = {tvar, _, X}) ->
case TVars == unrestricted orelse lists:member(X, TVars) of case TVars == unrestricted orelse lists:member(X, TVars) of
true -> ok; true -> ok;
false -> type_error({unbound_type_variable, T}) false -> type_error({unbound_type, T})
end, end,
T. T.
@@ -385,9 +385,10 @@ global_env() ->
{"FixedTTL", Fun1(Int, TTL)}, {"FixedTTL", Fun1(Int, TTL)},
%% Abort %% Abort
{"abort", Fun1(String, A)}, {"abort", Fun1(String, A)},
{"require", Fun([Bool, String], A)}]) {"require", Fun([Bool, String], Unit)}])
, types = MkDefs( , types = MkDefs(
[{"int", 0}, {"bool", 0}, {"char", 0}, {"string", 0}, {"address", 0}, [{"int", 0}, {"bool", 0}, {"char", 0}, {"string", 0}, {"address", 0},
{"unit", {[], {alias_t, Unit}}},
{"hash", {[], {alias_t, Bytes(32)}}}, {"hash", {[], {alias_t, Bytes(32)}}},
{"signature", {[], {alias_t, Bytes(64)}}}, {"signature", {[], {alias_t, Bytes(64)}}},
{"bits", 0}, {"bits", 0},
@@ -440,9 +441,9 @@ global_env() ->
{ funs = MkDefs( { funs = MkDefs(
[{"resolve", Fun([String, String], option_t(Ann, A))}, [{"resolve", Fun([String, String], option_t(Ann, A))},
{"preclaim", SignFun([Address, Hash], Unit)}, {"preclaim", SignFun([Address, Hash], Unit)},
{"claim", SignFun([Address, String, Int], Unit)}, {"claim", SignFun([Address, String, Int, Int], Unit)},
{"transfer", SignFun([Address, Address, Hash], Unit)}, {"transfer", SignFun([Address, Address, String], Unit)},
{"revoke", SignFun([Address, Hash], Unit)}]) }, {"revoke", SignFun([Address, String], Unit)}]) },
MapScope = #scope MapScope = #scope
{ funs = MkDefs( { funs = MkDefs(
@@ -2159,6 +2160,8 @@ pp_error({contract_has_no_entrypoints, Con}) ->
io_lib:format("The contract ~s (at ~s) has no entrypoints. Since Sophia version 3.2, public\n" io_lib:format("The contract ~s (at ~s) has no entrypoints. Since Sophia version 3.2, public\n"
"contract functions must be declared with the 'entrypoint' keyword instead of\n" "contract functions must be declared with the 'entrypoint' keyword instead of\n"
"'function'.\n", [pp_expr("", Con), pp_loc(Con)]); "'function'.\n", [pp_expr("", Con), pp_loc(Con)]);
pp_error({unbound_type, Type}) ->
io_lib:format("Unbound type ~s (at ~s).\n", [pp_type("", Type), pp_loc(Type)]);
pp_error(Err) -> pp_error(Err) ->
io_lib:format("Unknown error: ~p\n", [Err]). io_lib:format("Unknown error: ~p\n", [Err]).
@@ -2320,8 +2323,10 @@ pp({uvar, _, Ref}) ->
["?u" | integer_to_list(erlang:phash2(Ref, 16384)) ]; ["?u" | integer_to_list(erlang:phash2(Ref, 16384)) ];
pp({tvar, _, Name}) -> pp({tvar, _, Name}) ->
Name; Name;
pp({tuple_t, _, []}) ->
"unit";
pp({tuple_t, _, Cpts}) -> pp({tuple_t, _, Cpts}) ->
["(", pp(Cpts), ")"]; ["(", string:join(lists:map(fun pp/1, Cpts), " * "), ")"];
pp({bytes_t, _, any}) -> "bytes(_)"; pp({bytes_t, _, any}) -> "bytes(_)";
pp({bytes_t, _, Len}) -> pp({bytes_t, _, Len}) ->
["bytes(", integer_to_list(Len), ")"]; ["bytes(", integer_to_list(Len), ")"];
+45 -13
View File
@@ -183,7 +183,7 @@ builtins() ->
{["Oracle"], [{"register", 4}, {"query_fee", 1}, {"query", 5}, {"get_question", 2}, {["Oracle"], [{"register", 4}, {"query_fee", 1}, {"query", 5}, {"get_question", 2},
{"respond", 4}, {"extend", 3}, {"get_answer", 2}, {"respond", 4}, {"extend", 3}, {"get_answer", 2},
{"check", 1}, {"check_query", 2}]}, {"check", 1}, {"check_query", 2}]},
{["AENS"], [{"resolve", 2}, {"preclaim", 3}, {"claim", 4}, {"transfer", 4}, {["AENS"], [{"resolve", 2}, {"preclaim", 3}, {"claim", 5}, {"transfer", 4},
{"revoke", 3}]}, {"revoke", 3}]},
{["Map"], [{"from_list", 1}, {"to_list", 1}, {"lookup", 2}, {["Map"], [{"from_list", 1}, {"to_list", 1}, {"lookup", 2},
{"lookup_default", 3}, {"delete", 2}, {"member", 2}, {"size", 1}]}, {"lookup_default", 3}, {"delete", 2}, {"member", 2}, {"size", 1}]},
@@ -239,7 +239,8 @@ to_fcode(Env, [{contract, _, {con, _, Main}, Decls}]) ->
#{ contract_name => Main, #{ contract_name => Main,
state_type => StateType, state_type => StateType,
event_type => EventType, event_type => EventType,
functions => add_event_function(Env1, EventType, Funs) }; functions => add_init_function(Env1,
add_event_function(Env1, EventType, Funs)) };
to_fcode(Env, [{contract, _, {con, _, Con}, Decls} | Code]) -> to_fcode(Env, [{contract, _, {con, _, Con}, Decls} | Code]) ->
Env1 = decls_to_fcode(Env#{ context => {abstract_contract, Con} }, Decls), Env1 = decls_to_fcode(Env#{ context => {abstract_contract, Con} }, Decls),
to_fcode(Env1, Code); to_fcode(Env1, Code);
@@ -261,6 +262,11 @@ decls_to_fcode(Env, 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, {type_decl, _, _, _}) -> Env;
decl_to_fcode(Env = #{context := {main_contract, _}}, {fun_decl, Ann, {id, _, Name}, _}) ->
case proplists:get_value(no_code, maps:get(options, Env, []), false) of
false -> fcode_error({missing_definition, Name, lists:keydelete(entrypoint, 1, Ann)});
true -> Env
end;
decl_to_fcode(Env, {fun_decl, _, _, _}) -> Env; decl_to_fcode(Env, {fun_decl, _, _, _}) -> Env;
decl_to_fcode(Env, {type_def, _Ann, Name, Args, Def}) -> decl_to_fcode(Env, {type_def, _Ann, Name, Args, Def}) ->
typedef_to_fcode(Env, Name, Args, Def); typedef_to_fcode(Env, Name, Args, Def);
@@ -819,6 +825,19 @@ builtin_to_fcode(Builtin, Args) ->
false -> {builtin, Builtin, Args} false -> {builtin, Builtin, Args}
end. end.
%% -- Init function --
add_init_function(_Env, Funs) ->
InitName = {entrypoint, <<"init">>},
InitFun = #{ args := InitArgs } =
case maps:get(InitName, Funs, none) of
none -> #{ attrs => [], args => [], return => {tuple, []}, body => {tuple, []} };
Info -> Info
end,
Vars = [ {var, X} || {X, _} <- InitArgs ],
Funs#{ init => InitFun#{ return => {tuple, []},
body => {builtin, set_state, [{def, InitName, Vars}]} } }.
%% -- Event function -- %% -- Event function --
add_event_function(_Env, none, Funs) -> Funs; add_event_function(_Env, none, Funs) -> Funs;
@@ -1001,6 +1020,8 @@ add_fun_env(Env = #{ context := {abstract_contract, _} }, _) -> Env; %% no func
add_fun_env(Env = #{ fun_env := FunEnv }, Decls) -> add_fun_env(Env = #{ fun_env := FunEnv }, Decls) ->
Entry = fun({letfun, Ann, {id, _, Name}, Args, _, _}) -> Entry = fun({letfun, Ann, {id, _, Name}, Args, _, _}) ->
[{qname(Env, Name), {make_fun_name(Env, Ann, Name), length(Args)}}]; [{qname(Env, Name), {make_fun_name(Env, Ann, Name), length(Args)}}];
({fun_decl, Ann, {id, _, Name}, {fun_t, _, _, ArgTypes, _}}) ->
[{qname(Env, Name), {make_fun_name(Env, Ann, Name), length(ArgTypes)}}];
(_) -> [] end, (_) -> [] end,
FunEnv1 = maps:from_list(lists:flatmap(Entry, Decls)), FunEnv1 = maps:from_list(lists:flatmap(Entry, Decls)),
Env#{ fun_env := maps:merge(FunEnv, FunEnv1) }. Env#{ fun_env := maps:merge(FunEnv, FunEnv1) }.
@@ -1009,8 +1030,7 @@ make_fun_name(#{ context := Context }, Ann, Name) ->
Entrypoint = proplists:get_value(entrypoint, Ann, false), Entrypoint = proplists:get_value(entrypoint, Ann, false),
case Context of case Context of
{main_contract, Main} -> {main_contract, Main} ->
if Name == "init" -> init; if Entrypoint -> {entrypoint, list_to_binary(Name)};
Entrypoint -> {entrypoint, list_to_binary(Name)};
true -> {local_fun, [Main, Name]} true -> {local_fun, [Main, Name]}
end; end;
{namespace, Lib} -> {namespace, Lib} ->
@@ -1094,6 +1114,16 @@ pat_vars({tuple, Ps}) -> pat_vars(Ps);
pat_vars({con, _, _, Ps}) -> pat_vars(Ps); pat_vars({con, _, _, Ps}) -> pat_vars(Ps);
pat_vars(Ps) when is_list(Ps) -> [X || P <- Ps, X <- pat_vars(P)]. pat_vars(Ps) when is_list(Ps) -> [X || P <- Ps, X <- pat_vars(P)].
-spec fsplit_pat_vars(fsplit_pat()) -> [var_name()].
fsplit_pat_vars({var, X}) -> [X || X /= "_"];
fsplit_pat_vars({bool, _}) -> [];
fsplit_pat_vars({int, _}) -> [];
fsplit_pat_vars({string, _}) -> [];
fsplit_pat_vars(nil) -> [];
fsplit_pat_vars({'::', P, Q}) -> [P, Q];
fsplit_pat_vars({tuple, Ps}) -> Ps;
fsplit_pat_vars({con, _, _, Ps}) -> Ps.
free_vars(Xs) when is_list(Xs) -> free_vars(Xs) when is_list(Xs) ->
lists:umerge([ free_vars(X) || X <- Xs ]); lists:umerge([ free_vars(X) || X <- Xs ]);
free_vars(Expr) -> free_vars(Expr) ->
@@ -1119,7 +1149,7 @@ free_vars(Expr) ->
{switch, A} -> free_vars(A); {switch, A} -> free_vars(A);
{split, _, X, As} -> free_vars([{var, X} | As]); {split, _, X, As} -> free_vars([{var, X} | As]);
{nosplit, A} -> free_vars(A); {nosplit, A} -> free_vars(A);
{'case', P, A} -> free_vars(A) -- lists:sort(pat_vars(P)) {'case', P, A} -> free_vars(A) -- lists:sort(fsplit_pat_vars(P))
end. end.
get_named_args(NamedArgsT, Args) -> get_named_args(NamedArgsT, Args) ->
@@ -1278,14 +1308,17 @@ pp_fun(Name, #{ args := Args, return := Return, body := Body }) ->
pp_text(" : "), pp_ftype(Return), pp_text(" =")]), pp_text(" : "), pp_ftype(Return), pp_text(" =")]),
prettypr:nest(2, pp_fexpr(Body))). prettypr:nest(2, pp_fexpr(Body))).
pp_fun_name(init) -> pp_text(init); pp_fun_name(init) -> pp_text('INIT');
pp_fun_name(event) -> pp_text(event); pp_fun_name(event) -> pp_text(event);
pp_fun_name({entrypoint, E}) -> pp_text(binary_to_list(E)); pp_fun_name({entrypoint, E}) -> pp_text(binary_to_list(E));
pp_fun_name({local_fun, Q}) -> pp_text(string:join(Q, ".")). pp_fun_name({local_fun, Q}) -> pp_text(string:join(Q, ".")).
pp_text(<<>>) -> prettypr:text("\"\""); pp_text(<<>>) -> prettypr:text("\"\"");
pp_text(Bin) when is_binary(Bin) -> prettypr:text(lists:flatten(io_lib:format("~p", [binary_to_list(Bin)]))); pp_text(Bin) when is_binary(Bin) -> prettypr:text(lists:flatten(io_lib:format("~p", [binary_to_list(Bin)])));
pp_text(S) -> prettypr:text(lists:concat([S])). pp_text(S) when is_list(S) -> prettypr:text(lists:concat([S]));
pp_text(A) when is_atom(A) -> prettypr:text(atom_to_list(A)).
pp_int(I) -> prettypr:text(integer_to_list(I)).
pp_beside([]) -> prettypr:empty(); pp_beside([]) -> prettypr:empty();
pp_beside([X]) -> X; pp_beside([X]) -> X;
@@ -1317,18 +1350,18 @@ pp_fexpr(nil) ->
pp_fexpr({var, X}) -> pp_text(X); pp_fexpr({var, X}) -> pp_text(X);
pp_fexpr({def, Fun}) -> pp_fun_name(Fun); pp_fexpr({def, Fun}) -> pp_fun_name(Fun);
pp_fexpr({def_u, Fun, Ar}) -> pp_fexpr({def_u, Fun, Ar}) ->
pp_beside([pp_fun_name(Fun), pp_text("/"), pp_text(Ar)]); pp_beside([pp_fun_name(Fun), pp_text("/"), pp_int(Ar)]);
pp_fexpr({def, Fun, Args}) -> pp_fexpr({def, Fun, Args}) ->
pp_call(pp_fun_name(Fun), Args); pp_call(pp_fun_name(Fun), Args);
pp_fexpr({con, _, I, []}) -> pp_fexpr({con, _, I, []}) ->
pp_beside(pp_text("C"), pp_text(I)); pp_beside(pp_text("C"), pp_int(I));
pp_fexpr({con, _, I, Es}) -> pp_fexpr({con, _, I, Es}) ->
pp_beside(pp_fexpr({con, [], I, []}), pp_beside(pp_fexpr({con, [], I, []}),
pp_fexpr({tuple, Es})); pp_fexpr({tuple, Es}));
pp_fexpr({tuple, Es}) -> pp_fexpr({tuple, Es}) ->
pp_parens(pp_par(pp_punctuate(pp_text(","), [pp_fexpr(E) || E <- Es]))); pp_parens(pp_par(pp_punctuate(pp_text(","), [pp_fexpr(E) || E <- Es])));
pp_fexpr({proj, E, I}) -> pp_fexpr({proj, E, I}) ->
pp_beside([pp_fexpr(E), pp_text("."), pp_text(I)]); pp_beside([pp_fexpr(E), pp_text("."), pp_int(I)]);
pp_fexpr({lam, Xs, A}) -> pp_fexpr({lam, Xs, A}) ->
pp_par([pp_fexpr({tuple, [{var, X} || X <- Xs]}), pp_text("=>"), pp_par([pp_fexpr({tuple, [{var, X} || X <- Xs]}), pp_text("=>"),
prettypr:nest(2, pp_fexpr(A))]); prettypr:nest(2, pp_fexpr(A))]);
@@ -1339,7 +1372,7 @@ pp_fexpr({closure, Fun, ClEnv}) ->
end, end,
pp_call(pp_text("__CLOSURE__"), [{def, Fun} | FVs]); pp_call(pp_text("__CLOSURE__"), [{def, Fun} | FVs]);
pp_fexpr({set_proj, E, I, A}) -> pp_fexpr({set_proj, E, I, A}) ->
pp_beside(pp_fexpr(E), pp_braces(pp_beside([pp_text(I), pp_text(" = "), pp_fexpr(A)]))); pp_beside(pp_fexpr(E), pp_braces(pp_beside([pp_int(I), pp_text(" = "), pp_fexpr(A)])));
pp_fexpr({op, Op, [A, B] = Args}) -> pp_fexpr({op, Op, [A, B] = Args}) ->
case is_infix(Op) of case is_infix(Op) of
false -> pp_call(pp_text(Op), Args); false -> pp_call(pp_text(Op), Args);
@@ -1360,7 +1393,7 @@ pp_fexpr({builtin_u, B, N}) ->
pp_fexpr({builtin, B, As}) -> pp_fexpr({builtin, B, As}) ->
pp_call(pp_text(B), As); pp_call(pp_text(B), As);
pp_fexpr({remote_u, Ct, Fun, Ar}) -> pp_fexpr({remote_u, Ct, Fun, Ar}) ->
pp_beside([pp_fexpr(Ct), pp_text("."), pp_fun_name(Fun), pp_text("/"), pp_text(Ar)]); pp_beside([pp_fexpr(Ct), pp_text("."), pp_fun_name(Fun), pp_text("/"), pp_int(Ar)]);
pp_fexpr({remote, Ct, Fun, As}) -> pp_fexpr({remote, Ct, Fun, As}) ->
pp_call(pp_beside([pp_fexpr(Ct), pp_text("."), pp_fun_name(Fun)]), As); pp_call(pp_beside([pp_fexpr(Ct), pp_text("."), pp_fun_name(Fun)]), As);
pp_fexpr({funcall, Fun, As}) -> pp_fexpr({funcall, Fun, As}) ->
@@ -1415,4 +1448,3 @@ pp_pat(Pat) -> pp_fexpr(Pat).
is_infix(Op) -> is_infix(Op) ->
C = hd(atom_to_list(Op)), C = hd(atom_to_list(Op)),
C < $a orelse C > $z. C < $a orelse C > $z.
+19 -16
View File
@@ -21,18 +21,19 @@ convert_typed(TypedTree, Options) ->
{contract, _, {con, _, Con}, _} -> Con; {contract, _, {con, _, Con}, _} -> Con;
_ -> gen_error(last_declaration_must_be_contract) _ -> gen_error(last_declaration_must_be_contract)
end, end,
Icode = code(TypedTree, aeso_icode:set_name(Name, aeso_icode:new(Options))), NewIcode = aeso_icode:set_name(Name, aeso_icode:new(Options)),
Icode = code(TypedTree, NewIcode, Options),
deadcode_elimination(Icode). deadcode_elimination(Icode).
code([{contract, _Attribs, Con, Code}|Rest], Icode) -> code([{contract, _Attribs, Con, Code}|Rest], Icode, Options) ->
NewIcode = contract_to_icode(Code, aeso_icode:set_namespace(Con, Icode)), NewIcode = contract_to_icode(Code, aeso_icode:set_namespace(Con, Icode)),
code(Rest, NewIcode); code(Rest, NewIcode, Options);
code([{namespace, _Ann, Name, Code}|Rest], Icode) -> code([{namespace, _Ann, Name, Code}|Rest], Icode, Options) ->
%% TODO: nested namespaces %% TODO: nested namespaces
NewIcode = contract_to_icode(Code, aeso_icode:set_namespace(Name, Icode)), NewIcode = contract_to_icode(Code, aeso_icode:set_namespace(Name, Icode)),
code(Rest, NewIcode); code(Rest, NewIcode, Options);
code([], Icode) -> code([], Icode, Options) ->
add_default_init_function(add_builtins(Icode)). add_default_init_function(add_builtins(Icode), Options).
%% Generate error on correct format. %% Generate error on correct format.
@@ -40,10 +41,12 @@ gen_error(Error) ->
error({code_errors, [Error]}). error({code_errors, [Error]}).
%% Create default init function (only if state is unit). %% Create default init function (only if state is unit).
add_default_init_function(Icode = #{functions := Funs, state_type := State}) -> add_default_init_function(Icode = #{functions := Funs, state_type := State}, Options) ->
NoCode = proplists:get_value(no_code, Options, false),
{_, _, QInit} = aeso_icode:qualify({id, [], "init"}, Icode), {_, _, QInit} = aeso_icode:qualify({id, [], "init"}, Icode),
case lists:keymember(QInit, 1, Funs) of case lists:keymember(QInit, 1, Funs) of
true -> Icode; true -> Icode;
false when NoCode -> Icode;
false when State /= {tuple, []} -> false when State /= {tuple, []} ->
gen_error(missing_init_function); gen_error(missing_init_function);
false -> false ->
@@ -260,21 +263,21 @@ ast_body(?qid_app(["AENS", "preclaim"], Args, _, _), Icode) ->
[word, word, sign_t()], {tuple, []}); [word, word, sign_t()], {tuple, []});
ast_body(?qid_app(["AENS", "claim"], Args, _, _), Icode) -> ast_body(?qid_app(["AENS", "claim"], Args, _, _), Icode) ->
{Sign, [Addr, Name, Salt]} = get_signature_arg(Args), {Sign, [Addr, Name, Salt, NameFee]} = get_signature_arg(Args),
prim_call(?PRIM_CALL_AENS_CLAIM, #integer{value = 0}, prim_call(?PRIM_CALL_AENS_CLAIM, #integer{value = 0},
[ast_body(Addr, Icode), ast_body(Name, Icode), ast_body(Salt, Icode), ast_body(Sign, Icode)], [ast_body(Addr, Icode), ast_body(Name, Icode), ast_body(Salt, Icode), ast_body(Sign, Icode), ast_body(NameFee, Icode)],
[word, string, word, sign_t()], {tuple, []}); [word, string, word, sign_t(), word], {tuple, []});
ast_body(?qid_app(["AENS", "transfer"], Args, _, _), Icode) -> ast_body(?qid_app(["AENS", "transfer"], Args, _, _), Icode) ->
{Sign, [FromAddr, ToAddr, NameHash]} = get_signature_arg(Args), {Sign, [FromAddr, ToAddr, Name]} = get_signature_arg(Args),
prim_call(?PRIM_CALL_AENS_TRANSFER, #integer{value = 0}, prim_call(?PRIM_CALL_AENS_TRANSFER, #integer{value = 0},
[ast_body(FromAddr, Icode), ast_body(ToAddr, Icode), ast_body(NameHash, Icode), ast_body(Sign, Icode)], [ast_body(FromAddr, Icode), ast_body(ToAddr, Icode), ast_body(Name, Icode), ast_body(Sign, Icode)],
[word, word, word, sign_t()], {tuple, []}); [word, word, word, sign_t()], {tuple, []});
ast_body(?qid_app(["AENS", "revoke"], Args, _, _), Icode) -> ast_body(?qid_app(["AENS", "revoke"], Args, _, _), Icode) ->
{Sign, [Addr, NameHash]} = get_signature_arg(Args), {Sign, [Addr, Name]} = get_signature_arg(Args),
prim_call(?PRIM_CALL_AENS_REVOKE, #integer{value = 0}, prim_call(?PRIM_CALL_AENS_REVOKE, #integer{value = 0},
[ast_body(Addr, Icode), ast_body(NameHash, Icode), ast_body(Sign, Icode)], [ast_body(Addr, Icode), ast_body(Name, Icode), ast_body(Sign, Icode)],
[word, word, sign_t()], {tuple, []}); [word, word, sign_t()], {tuple, []});
ast_body({qid, _, ["AENS", "resolve"]}, _Icode) -> gen_error({underapplied_primitive, 'AENS.resolve'}); ast_body({qid, _, ["AENS", "resolve"]}, _Icode) -> gen_error({underapplied_primitive, 'AENS.resolve'});
@@ -728,7 +731,7 @@ ast_typerep({con, _, _}, _) ->
word; %% Contract type word; %% Contract type
ast_typerep({bytes_t, _, Len}, _) -> ast_typerep({bytes_t, _, Len}, _) ->
bytes_t(Len); bytes_t(Len);
ast_typerep({app_t, _, {id, _, Name}, Args}, Icode) -> ast_typerep({app_t, _, {I, _, Name}, Args}, Icode) when I =:= id; I =:= qid ->
ArgReps = [ ast_typerep(Arg, Icode) || Arg <- Args ], ArgReps = [ ast_typerep(Arg, Icode) || Arg <- Args ],
lookup_type_id(Name, ArgReps, Icode); lookup_type_id(Name, ArgReps, Icode);
ast_typerep({tvar,_,A}, #{ type_vars := TypeVars }) -> ast_typerep({tvar,_,A}, #{ type_vars := TypeVars }) ->
+19 -7
View File
@@ -35,6 +35,7 @@
| pp_icode | pp_icode
| pp_assembler | pp_assembler
| pp_bytecode | pp_bytecode
| no_code
| {backend, aevm | fate} | {backend, aevm | fate}
| {include, {file_system, [string()]} | | {include, {file_system, [string()]} |
{explicit_files, #{string() => binary()}}} {explicit_files, #{string() => binary()}}}
@@ -120,7 +121,8 @@ from_string1(aevm, ContractString, Options) ->
{ok, #{byte_code => ByteCode, {ok, #{byte_code => ByteCode,
compiler_version => Version, compiler_version => Version,
contract_source => ContractString, contract_source => ContractString,
type_info => TypeInfo type_info => TypeInfo,
abi_version => aeb_aevm_abi:abi_version()
}}; }};
from_string1(fate, ContractString, Options) -> from_string1(fate, ContractString, Options) ->
#{fcode := FCode} = string_to_code(ContractString, Options), #{fcode := FCode} = string_to_code(ContractString, Options),
@@ -131,10 +133,11 @@ from_string1(fate, ContractString, Options) ->
compiler_version => Version, compiler_version => Version,
contract_source => ContractString, contract_source => ContractString,
type_info => [], type_info => [],
fate_code => FateCode fate_code => FateCode,
abi_version => aeb_fate_abi:abi_version()
}}. }}.
-spec string_to_code(string(), [option()]) -> map(). -spec string_to_code(string(), options()) -> map().
string_to_code(ContractString, Options) -> string_to_code(ContractString, Options) ->
Ast = parse(ContractString, Options), Ast = parse(ContractString, Options),
pp_sophia_code(Ast, Options), pp_sophia_code(Ast, Options),
@@ -290,12 +293,19 @@ to_sophia_value(ContractString, Fun, ResType, Data) ->
{ok, aeso_syntax:expr()} | {error, term()}. {ok, aeso_syntax:expr()} | {error, term()}.
to_sophia_value(_, _, error, Err, _Options) -> to_sophia_value(_, _, error, Err, _Options) ->
{ok, {app, [], {id, [], "error"}, [{string, [], Err}]}}; {ok, {app, [], {id, [], "error"}, [{string, [], Err}]}};
to_sophia_value(_, _, revert, Data, _Options) -> to_sophia_value(_, _, revert, Data, Options) ->
case proplists:get_value(backend, Options, aevm) of
aevm ->
case aeb_heap:from_binary(string, Data) of case aeb_heap:from_binary(string, Data) of
{ok, Err} -> {ok, {app, [], {id, [], "abort"}, [{string, [], Err}]}}; {ok, Err} -> {ok, {app, [], {id, [], "abort"}, [{string, [], Err}]}};
{error, _} = Err -> Err {error, _} = Err -> Err
end; end;
to_sophia_value(ContractString, FunName, ok, Data, Options) -> fate ->
Err = aeb_fate_encoding:deserialize(Data),
{ok, {app, [], {id, [], "abort"}, [{string, [], Err}]}}
end;
to_sophia_value(ContractString, FunName, ok, Data, Options0) ->
Options = [no_code | Options0],
try try
Code = string_to_code(ContractString, Options), Code = string_to_code(ContractString, Options),
#{ typed_ast := TypedAst, type_env := TypeEnv} = Code, #{ typed_ast := TypedAst, type_env := TypeEnv} = Code,
@@ -355,7 +365,8 @@ create_calldata(Code, Fun, Args) ->
-spec create_calldata(string(), string(), [string()], [{atom(), any()}]) -> -spec create_calldata(string(), string(), [string()], [{atom(), any()}]) ->
{ok, binary()} {ok, binary()}
| {error, term()}. | {error, term()}.
create_calldata(Code, Fun, Args, Options) -> create_calldata(Code, Fun, Args, Options0) ->
Options = [no_code | Options0],
case proplists:get_value(backend, Options, aevm) of case proplists:get_value(backend, Options, aevm) of
aevm -> aevm ->
case check_call(Code, Fun, Args, Options) of case check_call(Code, Fun, Args, Options) of
@@ -377,7 +388,8 @@ create_calldata(Code, Fun, Args, Options) ->
decode_calldata(ContractString, FunName, Calldata) -> decode_calldata(ContractString, FunName, Calldata) ->
decode_calldata(ContractString, FunName, Calldata, [{backend, aevm}]). decode_calldata(ContractString, FunName, Calldata, [{backend, aevm}]).
decode_calldata(ContractString, FunName, Calldata, Options) -> decode_calldata(ContractString, FunName, Calldata, Options0) ->
Options = [no_code | Options0],
try try
Code = string_to_code(ContractString, Options), Code = string_to_code(ContractString, Options),
#{ typed_ast := TypedAst, type_env := TypeEnv} = Code, #{ typed_ast := TypedAst, type_env := TypeEnv} = Code,
+10 -7
View File
@@ -139,7 +139,7 @@ compile(FCode, Options) ->
make_function_id(X) -> make_function_id(X) ->
aeb_fate_code:symbol_identifier(make_function_name(X)). aeb_fate_code:symbol_identifier(make_function_name(X)).
make_function_name(init) -> <<"init">>; make_function_name(init) -> <<"INIT">>;
make_function_name(event) -> <<"Chain.event">>; make_function_name(event) -> <<"Chain.event">>;
make_function_name({entrypoint, Name}) -> Name; make_function_name({entrypoint, Name}) -> Name;
make_function_name({local_fun, Xs}) -> list_to_binary("." ++ string:join(Xs, ".")). make_function_name({local_fun, Xs}) -> list_to_binary("." ++ string:join(Xs, ".")).
@@ -196,7 +196,7 @@ add_default_init_function(SFuns, StateType) when StateType /= {tuple, []} ->
SFuns; SFuns;
add_default_init_function(SFuns, {tuple, []}) -> add_default_init_function(SFuns, {tuple, []}) ->
%% Only add default if the init function is not present %% Only add default if the init function is not present
InitName = make_function_name(init), InitName = make_function_name({entrypoint, <<"init">>}),
case maps:find(InitName, SFuns) of case maps:find(InitName, SFuns) of
{ok, _} -> {ok, _} ->
SFuns; SFuns;
@@ -547,8 +547,8 @@ builtin_to_scode(Env, aens_resolve, [_Name, _Key, _Type] = Args) ->
builtin_to_scode(Env, aens_preclaim, [_Sign, _Account, _Hash] = Args) -> builtin_to_scode(Env, aens_preclaim, [_Sign, _Account, _Hash] = Args) ->
call_to_scode(Env, [aeb_fate_ops:aens_preclaim(?a, ?a, ?a), call_to_scode(Env, [aeb_fate_ops:aens_preclaim(?a, ?a, ?a),
tuple(0)], Args); tuple(0)], Args);
builtin_to_scode(Env, aens_claim, [_Sign, _Account, _NameString, _Salt] = Args) -> builtin_to_scode(Env, aens_claim, [_Sign, _Account, _NameString, _Salt, _NameFee] = Args) ->
call_to_scode(Env, [aeb_fate_ops:aens_claim(?a, ?a, ?a, ?a), call_to_scode(Env, [aeb_fate_ops:aens_claim(?a, ?a, ?a, ?a, ?a),
tuple(0)], Args); tuple(0)], Args);
builtin_to_scode(Env, aens_transfer, [_Sign, _From, _To, _Name] = Args) -> builtin_to_scode(Env, aens_transfer, [_Sign, _From, _To, _Name] = Args) ->
call_to_scode(Env, [aeb_fate_ops:aens_transfer(?a, ?a, ?a, ?a), call_to_scode(Env, [aeb_fate_ops:aens_transfer(?a, ?a, ?a, ?a),
@@ -866,7 +866,7 @@ attributes(I) ->
{'ORACLE_QUERY_FEE', A, B} -> Impure(A, [B]); {'ORACLE_QUERY_FEE', A, B} -> Impure(A, [B]);
{'AENS_RESOLVE', A, B, C, D} -> Impure(A, [B, C, D]); {'AENS_RESOLVE', A, B, C, D} -> Impure(A, [B, C, D]);
{'AENS_PRECLAIM', A, B, C} -> Impure(none, [A, B, C]); {'AENS_PRECLAIM', A, B, C} -> Impure(none, [A, B, C]);
{'AENS_CLAIM', A, B, C, D} -> Impure(none, [A, B, C, D]); {'AENS_CLAIM', A, B, C, D, E} -> Impure(none, [A, B, C, D, E]);
'AENS_UPDATE' -> Impure(none, []);%% TODO 'AENS_UPDATE' -> Impure(none, []);%% TODO
{'AENS_TRANSFER', A, B, C, D} -> Impure(none, [A, B, C, D]); {'AENS_TRANSFER', A, B, C, D} -> Impure(none, [A, B, C, D]);
{'AENS_REVOKE', A, B, C} -> Impure(none, [A, B, C]); {'AENS_REVOKE', A, B, C} -> Impure(none, [A, B, C]);
@@ -1340,7 +1340,7 @@ block(Blk = #blk{code = [{switch, Arg, Type, Alts, Default} | Code],
{DefRef, DefBlk} = {DefRef, DefBlk} =
case Default of case Default of
missing when Catchall == none -> missing when Catchall == none ->
FreshBlk([aeb_fate_ops:abort(?i(<<"Incomplete patterns">>))], none); FreshBlk([aeb_fate_ops:exit(?i(<<"Incomplete patterns">>))], none);
missing -> {Catchall, []}; missing -> {Catchall, []};
_ -> FreshBlk(Default ++ [{jump, RestRef}], Catchall) _ -> FreshBlk(Default ++ [{jump, RestRef}], Catchall)
%% ^ fall-through to the outer catchall %% ^ fall-through to the outer catchall
@@ -1415,6 +1415,7 @@ reorder_blocks(Ref, Code, Blocks, Acc) ->
[{'CALL_T', _}|_] -> reorder_blocks(Blocks, Acc1); [{'CALL_T', _}|_] -> reorder_blocks(Blocks, Acc1);
[{'CALL_TR', _, _, _}|_] -> reorder_blocks(Blocks, Acc1); [{'CALL_TR', _, _, _}|_] -> reorder_blocks(Blocks, Acc1);
[{'CALL_GTR', _, _, _}|_] -> reorder_blocks(Blocks, Acc1); [{'CALL_GTR', _, _, _}|_] -> reorder_blocks(Blocks, Acc1);
[{'EXIT', _}|_] -> reorder_blocks(Blocks, Acc1);
[{'ABORT', _}|_] -> reorder_blocks(Blocks, Acc1); [{'ABORT', _}|_] -> reorder_blocks(Blocks, Acc1);
[{switch, _, _}|_] -> reorder_blocks(Blocks, Acc1); [{switch, _, _}|_] -> reorder_blocks(Blocks, Acc1);
[{jump, L}|_] -> [{jump, L}|_] ->
@@ -1459,6 +1460,7 @@ tweak_returns(['RETURN' | Code = [{'CALL_TR', _, _, _} | _]]) -> Code;
tweak_returns(['RETURN' | Code = [{'CALL_GT', _} | _]]) -> Code; tweak_returns(['RETURN' | Code = [{'CALL_GT', _} | _]]) -> Code;
tweak_returns(['RETURN' | Code = [{'CALL_GTR', _, _, _, _} | _]]) -> Code; tweak_returns(['RETURN' | Code = [{'CALL_GTR', _, _, _, _} | _]]) -> Code;
tweak_returns(['RETURN' | Code = [{'ABORT', _} | _]]) -> Code; tweak_returns(['RETURN' | Code = [{'ABORT', _} | _]]) -> Code;
tweak_returns(['RETURN' | Code = [{'EXIT', _} | _]]) -> Code;
tweak_returns(Code) -> Code. tweak_returns(Code) -> Code.
%% -- Split basic blocks at CALL instructions -- %% -- Split basic blocks at CALL instructions --
@@ -1476,6 +1478,8 @@ split_calls(Ref, [I | Code], Acc, Blocks) when element(1, I) == 'CALL';
split_calls(make_ref(), Code, [], [{Ref, lists:reverse([I | Acc])} | Blocks]); split_calls(make_ref(), Code, [], [{Ref, lists:reverse([I | Acc])} | Blocks]);
split_calls(Ref, [{'ABORT', _} = I | _Code], Acc, Blocks) -> split_calls(Ref, [{'ABORT', _} = I | _Code], Acc, Blocks) ->
lists:reverse([{Ref, lists:reverse([I | Acc])} | Blocks]); lists:reverse([{Ref, lists:reverse([I | Acc])} | Blocks]);
split_calls(Ref, [{'EXIT', _} = I | _Code], Acc, Blocks) ->
lists:reverse([{Ref, lists:reverse([I | Acc])} | Blocks]);
split_calls(Ref, [I | Code], Acc, Blocks) -> split_calls(Ref, [I | Code], Acc, Blocks) ->
split_calls(Ref, Code, [I | Acc], Blocks). split_calls(Ref, Code, [I | Acc], Blocks).
@@ -1497,4 +1501,3 @@ set_labels(_, I) -> I.
with_ixs(Xs) -> with_ixs(Xs) ->
lists:zip(lists:seq(0, length(Xs) - 1), Xs). lists:zip(lists:seq(0, length(Xs) - 1), Xs).
+12 -8
View File
@@ -140,7 +140,8 @@ type100() -> type200().
type200() -> type200() ->
?RULE(many({fun_domain(), keyword('=>')}), type300(), fun_t(_1, _2)). ?RULE(many({fun_domain(), keyword('=>')}), type300(), fun_t(_1, _2)).
type300() -> type400(). type300() ->
?RULE(sep1(type400(), tok('*')), tuple_t(get_ann(lists:nth(1, _1)), _1)).
type400() -> type400() ->
choice( choice(
@@ -155,11 +156,18 @@ type400() ->
typeAtom() -> typeAtom() ->
?LAZY_P(choice( ?LAZY_P(choice(
[ id(), token(con), token(qcon), token(qid), tvar() [ parens(type())
, ?RULE(keyword('('), comma_sep(type()), tok(')'), tuple_t(_1, _2)) , id(), token(con), token(qcon), token(qid), tvar()
])). ])).
fun_domain() -> ?RULE(?LAZY_P(type300()), fun_domain(_1)). fun_domain() -> ?LAZY_P(choice(
[ ?RULE(tok('('), tok(')'), [])
%% Note avoidance of ambiguity: `(int)` can be treated as:
%% - literally `int`
%% - list of arguments with just one element int. This approach is dropped.
, ?RULE(tok('('), type(), tok(','), sep1(type(), tok(',')), tok(')'), [_2|_4])
, ?RULE(type300(), [_1])
])).
%% -- Statements ------------------------------------------------------------- %% -- Statements -------------------------------------------------------------
@@ -473,10 +481,6 @@ fun_t(Domains, Type) ->
tuple_e(_Ann, [Expr]) -> Expr; %% Not a tuple tuple_e(_Ann, [Expr]) -> Expr; %% Not a tuple
tuple_e(Ann, Exprs) -> {tuple, Ann, Exprs}. tuple_e(Ann, Exprs) -> {tuple, Ann, Exprs}.
%% TODO: not nice
fun_domain({tuple_t, _, Args}) -> Args;
fun_domain(T) -> [T].
-spec parse_pattern(aeso_syntax:expr()) -> aeso_parse_lib:parser(aeso_syntax:pat()). -spec parse_pattern(aeso_syntax:expr()) -> aeso_parse_lib:parser(aeso_syntax:pat()).
parse_pattern({app, Ann, Con = {'::', _}, Es}) -> parse_pattern({app, Ann, Con = {'::', _}, Es}) ->
{app, Ann, Con, lists:map(fun parse_pattern/1, Es)}; {app, Ann, Con, lists:map(fun parse_pattern/1, Es)};
+15 -5
View File
@@ -222,7 +222,7 @@ typedef({variant_t, Constructors}) ->
-spec constructor_t(aeso_syntax:constructor_t()) -> doc(). -spec constructor_t(aeso_syntax:constructor_t()) -> doc().
constructor_t({constr_t, _, C, []}) -> name(C); constructor_t({constr_t, _, C, []}) -> name(C);
constructor_t({constr_t, _, C, Args}) -> beside(name(C), tuple_type(Args)). constructor_t({constr_t, _, C, Args}) -> beside(name(C), args_type(Args)).
-spec field_t(aeso_syntax:field_t()) -> doc(). -spec field_t(aeso_syntax:field_t()) -> doc().
field_t({field_t, _, Name, Type}) -> field_t({field_t, _, Name, Type}) ->
@@ -234,11 +234,11 @@ type(Type, Options) ->
-spec type(aeso_syntax:type()) -> doc(). -spec type(aeso_syntax:type()) -> doc().
type({fun_t, _, Named, Args, Ret}) -> type({fun_t, _, Named, Args, Ret}) ->
follow(hsep(tuple_type(Named ++ Args), text("=>")), type(Ret)); follow(hsep(args_type(Named ++ Args), text("=>")), type(Ret));
type({app_t, _, Type, []}) -> type({app_t, _, Type, []}) ->
type(Type); type(Type);
type({app_t, _, Type, Args}) -> type({app_t, _, Type, Args}) ->
beside(type(Type), tuple_type(Args)); beside(type(Type), args_type(Args));
type({tuple_t, _, Args}) -> type({tuple_t, _, Args}) ->
tuple_type(Args); tuple_type(Args);
type({bytes_t, _, any}) -> text("bytes(_)"); type({bytes_t, _, any}) -> text("bytes(_)");
@@ -256,10 +256,20 @@ type(T = {con, _, _}) -> name(T);
type(T = {qcon, _, _}) -> name(T); type(T = {qcon, _, _}) -> name(T);
type(T = {tvar, _, _}) -> name(T). type(T = {tvar, _, _}) -> name(T).
-spec tuple_type([aeso_syntax:type()]) -> doc(). -spec args_type([aeso_syntax:type()]) -> doc().
tuple_type(Args) -> args_type(Args) ->
tuple(lists:map(fun type/1, Args)). tuple(lists:map(fun type/1, Args)).
-spec tuple_type([aeso_syntax:type()]) -> doc().
tuple_type([]) ->
text("unit");
tuple_type(Factors) ->
beside(
[ text("(")
, par(punctuate(text(" *"), lists:map(fun type/1, Factors)), 0)
, text(")")
]).
-spec arg_expr(aeso_syntax:arg_expr()) -> doc(). -spec arg_expr(aeso_syntax:arg_expr()) -> doc().
arg_expr({named_arg, _, Name, E}) -> arg_expr({named_arg, _, Name, E}) ->
follow(hsep(expr(Name), text("=")), expr(E)); follow(hsep(expr(Name), text("=")), expr(E));
+4 -4
View File
@@ -66,7 +66,7 @@ encode_decode_sophia_test() ->
ok = Check("bool", "true"), ok = Check("bool", "true"),
ok = Check("bool", "false"), ok = Check("bool", "false"),
ok = Check("string", "\"Hello\""), ok = Check("string", "\"Hello\""),
ok = Check("(string, list(int), option(bool))", ok = Check("string * list(int) * option(bool)",
"(\"Hello\", [1, 2, 3], Some(true))"), "(\"Hello\", [1, 2, 3], Some(true))"),
ok = Check("variant", "Blue({[\"x\"] = 1})"), ok = Check("variant", "Blue({[\"x\"] = 1})"),
ok = Check("r", "{x = (\"foo\", 0), y = Red}"), ok = Check("r", "{x = (\"foo\", 0), y = Red}"),
@@ -76,7 +76,7 @@ encode_decode_sophia_string(SophiaType, String) ->
io:format("String ~p~n", [String]), io:format("String ~p~n", [String]),
Code = [ "contract MakeCall =\n" Code = [ "contract MakeCall =\n"
, " type arg_type = ", SophiaType, "\n" , " type arg_type = ", SophiaType, "\n"
, " type an_alias('a) = (string, 'a)\n" , " type an_alias('a) = string * 'a\n"
, " record r = {x : an_alias(int), y : variant}\n" , " record r = {x : an_alias(int), y : variant}\n"
, " datatype variant = Red | Blue(map(string, int))\n" , " datatype variant = Red | Blue(map(string, int))\n"
, " entrypoint foo : arg_type => arg_type\n" ], , " entrypoint foo : arg_type => arg_type\n" ],
@@ -137,10 +137,10 @@ parameterized_contract(FunName, Types) ->
parameterized_contract(ExtraCode, FunName, Types) -> parameterized_contract(ExtraCode, FunName, Types) ->
lists:flatten( lists:flatten(
["contract Remote =\n" ["contract Remote =\n"
" entrypoint bla : () => ()\n\n" " entrypoint bla : () => unit\n\n"
"contract Dummy =\n", "contract Dummy =\n",
ExtraCode, "\n", ExtraCode, "\n",
" type an_alias('a) = (string, 'a)\n" " type an_alias('a) = string * 'a\n"
" record r = {x : an_alias(int), y : variant}\n" " record r = {x : an_alias(int), y : variant}\n"
" datatype variant = Red | Blue(map(string, int))\n" " datatype variant = Red | Blue(map(string, int))\n"
" entrypoint ", FunName, " : (", string:join(Types, ", "), ") => int\n" ]). " entrypoint ", FunName, " : (", string:join(Types, ", "), ") => int\n" ]).
+3 -3
View File
@@ -53,7 +53,7 @@ test_cases(2) ->
{Contract,MapACI,DecACI}; {Contract,MapACI,DecACI};
test_cases(3) -> test_cases(3) ->
Contract = <<"contract C =\n" Contract = <<"contract C =\n"
" type state = ()\n" " type state = unit\n"
" datatype event = SingleEventDefined\n" " datatype event = SingleEventDefined\n"
" datatype bert('a) = Bin('a)\n" " datatype bert('a) = Bin('a)\n"
" entrypoint a(i : bert(string)) = 1\n">>, " entrypoint a(i : bert(string)) = 1\n">>,
@@ -67,7 +67,7 @@ test_cases(3) ->
stateful => false}], stateful => false}],
name => <<"C">>, name => <<"C">>,
event => #{variant => [#{<<"SingleEventDefined">> => []}]}, event => #{variant => [#{<<"SingleEventDefined">> => []}]},
state => #{tuple => []}, state => <<"unit">>,
type_defs => type_defs =>
[#{name => <<"bert">>, [#{name => <<"bert">>,
typedef => typedef =>
@@ -75,7 +75,7 @@ test_cases(3) ->
[#{<<"Bin">> => [<<"'a">>]}]}, [#{<<"Bin">> => [<<"'a">>]}]},
vars => [#{name => <<"'a">>}]}]}}, vars => [#{name => <<"'a">>}]}]}},
DecACI = <<"contract C =\n" DecACI = <<"contract C =\n"
" type state = ()\n" " type state = unit\n"
" datatype event = SingleEventDefined\n" " datatype event = SingleEventDefined\n"
" datatype bert('a) = Bin('a)\n" " datatype bert('a) = Bin('a)\n"
" entrypoint a : (C.bert(string)) => int\n">>, " entrypoint a : (C.bert(string)) => int\n">>,
+31 -5
View File
@@ -36,10 +36,34 @@ calldata_test_() ->
end end
end} || {ContractName, Fun, Args} <- compilable_contracts()]. end} || {ContractName, Fun, Args} <- compilable_contracts()].
calldata_aci_test_() ->
[ {"Testing " ++ ContractName ++ " contract calling " ++ Fun,
fun() ->
ContractString = aeso_test_utils:read_contract(ContractName),
{ok, ContractACIBin} = aeso_aci:contract_interface(string, ContractString),
ContractACI = binary_to_list(ContractACIBin),
io:format("ACI:\n~s\n", [ContractACIBin]),
AevmExprs =
case not lists:member(ContractName, not_yet_compilable(aevm)) of
true -> ast_exprs(ContractACI, Fun, Args, [{backend, aevm}]);
false -> undefined
end,
FateExprs =
case not lists:member(ContractName, not_yet_compilable(fate)) of
true -> ast_exprs(ContractACI, Fun, Args, [{backend, fate}]);
false -> undefined
end,
case FateExprs == undefined orelse AevmExprs == undefined of
true -> ok;
false ->
?assertEqual(FateExprs, AevmExprs)
end
end} || {ContractName, Fun, Args} <- compilable_contracts()].
ast_exprs(ContractString, Fun, Args, Opts) -> ast_exprs(ContractString, Fun, Args, Opts) ->
{ok, Data} = aeso_compiler:create_calldata(ContractString, Fun, Args, Opts), {ok, Data} = (catch aeso_compiler:create_calldata(ContractString, Fun, Args, Opts)),
{ok, _Types, Exprs} = aeso_compiler:decode_calldata(ContractString, Fun, Data, Opts), {ok, _Types, Exprs} = (catch aeso_compiler:decode_calldata(ContractString, Fun, Data, Opts)),
?assert(is_list(Exprs)), ?assert(is_list(Exprs)),
Exprs. Exprs.
@@ -93,10 +117,12 @@ compilable_contracts() ->
{"complex_types", "init", ["ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ"]}, {"complex_types", "init", ["ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ"]},
{"__call" "init", []}, {"__call" "init", []},
{"bitcoin_auth", "authorize", ["1", "#0102030405060708090a0b0c0d0e0f101718192021222324252627282930313233343536373839401a1b1c1d1e1f202122232425262728293031323334353637"]}, {"bitcoin_auth", "authorize", ["1", "#0102030405060708090a0b0c0d0e0f101718192021222324252627282930313233343536373839401a1b1c1d1e1f202122232425262728293031323334353637"]},
{"bitcoin_auth", "to_sign", ["#0102030405060708090a0b0c0d0e0f1017181920212223242526272829303132", "2"]} {"bitcoin_auth", "to_sign", ["#0102030405060708090a0b0c0d0e0f1017181920212223242526272829303132", "2"]},
{"stub", "foo", ["42"]},
{"stub", "foo", ["-42"]}
]. ].
not_yet_compilable(fate) -> not_yet_compilable(fate) ->
["address_chain"]; [];
not_yet_compilable(aevm) -> not_yet_compilable(aevm) ->
["__call"]. [].
+6 -5
View File
@@ -117,7 +117,8 @@ compilable_contracts() ->
"address_chain", "address_chain",
"namespace_bug", "namespace_bug",
"bytes_to_x", "bytes_to_x",
"aens" "aens",
"tuple_match"
]. ].
not_yet_compilable(fate) -> []; not_yet_compilable(fate) -> [];
@@ -220,7 +221,7 @@ failing_contracts() ->
"when checking that 'init' returns a value of type 'state' at line 7, column 3">>]} "when checking that 'init' returns a value of type 'state' at line 7, column 3">>]}
, {"missing_state_type", , {"missing_state_type",
[<<"Cannot unify string\n" [<<"Cannot unify string\n"
" and ()\n" " and unit\n"
"when checking that 'init' returns a value of type 'state' at line 5, column 3">>]} "when checking that 'init' returns a value of type 'state' at line 5, column 3">>]}
, {"missing_fields_in_record_expression", , {"missing_fields_in_record_expression",
[<<"The field x is missing when constructing an element of type r('a) (at line 7, column 42)">>, [<<"The field x is missing when constructing an element of type r('a) (at line 7, column 42)">>,
@@ -325,7 +326,7 @@ failing_contracts() ->
<<"Cannot reference stateful function local_spend (at line 14, column 35)\nin the definition of non-stateful function fail2.">>, <<"Cannot reference stateful function local_spend (at line 14, column 35)\nin the definition of non-stateful function fail2.">>,
<<"Cannot reference stateful function Chain.spend (at line 16, column 15)\nin the definition of non-stateful function fail3.">>, <<"Cannot reference stateful function Chain.spend (at line 16, column 15)\nin the definition of non-stateful function fail3.">>,
<<"Cannot reference stateful function Chain.spend (at line 20, column 31)\nin the definition of non-stateful function fail4.">>, <<"Cannot reference stateful function Chain.spend (at line 20, column 31)\nin the definition of non-stateful function fail4.">>,
<<"Cannot reference stateful function Chain.spend (at line 35, column 45)\nin the definition of non-stateful function fail5.">>, <<"Cannot reference stateful function Chain.spend (at line 35, column 47)\nin the definition of non-stateful function fail5.">>,
<<"Cannot pass non-zero value argument 1000 (at line 48, column 57)\nin the definition of non-stateful function fail6.">>, <<"Cannot pass non-zero value argument 1000 (at line 48, column 57)\nin the definition of non-stateful function fail6.">>,
<<"Cannot pass non-zero value argument 1000 (at line 49, column 56)\nin the definition of non-stateful function fail7.">>, <<"Cannot pass non-zero value argument 1000 (at line 49, column 56)\nin the definition of non-stateful function fail7.">>,
<<"Cannot pass non-zero value argument 1000 (at line 52, column 17)\nin the definition of non-stateful function fail8.">>]} <<"Cannot pass non-zero value argument 1000 (at line 52, column 17)\nin the definition of non-stateful function fail8.">>]}
@@ -350,7 +351,7 @@ failing_contracts() ->
<<"Namespaces cannot contain entrypoints (at line 3, column 3). Use 'function' instead.">>, <<"Namespaces cannot contain entrypoints (at line 3, column 3). Use 'function' instead.">>,
<<"The contract Remote (at line 5, column 10) has no entrypoints. Since Sophia version 3.2, public\ncontract functions must be declared with the 'entrypoint' keyword instead of\n'function'.">>, <<"The contract Remote (at line 5, column 10) has no entrypoints. Since Sophia version 3.2, public\ncontract functions must be declared with the 'entrypoint' keyword instead of\n'function'.">>,
<<"The entrypoint wha (at line 12, column 3) cannot be private. Use 'function' instead.">>, <<"The entrypoint wha (at line 12, column 3) cannot be private. Use 'function' instead.">>,
<<"Use 'entrypoint' for declaration of foo (at line 6, column 3):\n entrypoint foo : () => ()">>, <<"Use 'entrypoint' for declaration of foo (at line 6, column 3):\n entrypoint foo : () => unit">>,
<<"Use 'entrypoint' instead of 'function' for public function foo (at line 10, column 3):\n entrypoint foo() = ()">>, <<"Use 'entrypoint' instead of 'function' for public function foo (at line 10, column 3):\n entrypoint foo() = ()">>,
<<"Use 'entrypoint' instead of 'function' for public function foo (at line 6, column 3):\n entrypoint foo : () => ()">>]} <<"Use 'entrypoint' instead of 'function' for public function foo (at line 6, column 3):\n entrypoint foo : () => unit">>]}
]. ].
+1 -1
View File
@@ -8,7 +8,7 @@ contract AbortTest =
{ value = v } { value = v }
// Aborting // Aborting
public function do_abort(v : int, s : string) : () = public function do_abort(v : int, s : string) : unit =
put_value(v) put_value(v)
revert_abort(s) revert_abort(s)
+3 -3
View File
@@ -1,9 +1,9 @@
contract Interface = contract Interface =
function do_abort : (int, string) => () function do_abort : (int, string) => unit
function get_value : () => int function get_value : () => int
function put_value : (int) => () function put_value : (int) => unit
function get_values : () => list(int) function get_values : () => list(int)
function put_values : (int) => () function put_values : (int) => unit
contract AbortTestInt = contract AbortTestInt =
+1 -1
View File
@@ -1,5 +1,5 @@
contract Remote = contract Remote =
entrypoint main : (int) => () entrypoint main : (int) => unit
contract AddrChain = contract AddrChain =
type o_type = oracle(string, map(string, int)) type o_type = oracle(string, map(string, int))
+1 -1
View File
@@ -1,6 +1,6 @@
contract Remote = contract Remote =
entrypoint foo : () => () entrypoint foo : () => unit
contract AddressLiterals = contract AddressLiterals =
entrypoint addr() : address = entrypoint addr() : address =
+18 -17
View File
@@ -12,44 +12,45 @@ contract AENSTest =
// Transactions // Transactions
stateful entrypoint preclaim(addr : address, // Claim on behalf of this account (can be Contract.address) stateful entrypoint preclaim(addr : address, // Claim on behalf of this account (can be Contract.address)
chash : hash) : () = // Commitment hash chash : hash) : unit = // Commitment hash
AENS.preclaim(addr, chash) AENS.preclaim(addr, chash)
stateful entrypoint signedPreclaim(addr : address, // Claim on behalf of this account (can be Contract.address) stateful entrypoint signedPreclaim(addr : address, // Claim on behalf of this account (can be Contract.address)
chash : hash, // Commitment hash chash : hash, // Commitment hash
sign : signature) : () = // Signed by addr (if not Contract.address) sign : signature) : unit = // Signed by addr (if not Contract.address)
AENS.preclaim(addr, chash, signature = sign) AENS.preclaim(addr, chash, signature = sign)
stateful entrypoint claim(addr : address, stateful entrypoint claim(addr : address,
name : string, name : string,
salt : int) : () = salt : int,
AENS.claim(addr, name, salt) name_fee : int) : unit =
AENS.claim(addr, name, salt, name_fee)
stateful entrypoint signedClaim(addr : address, stateful entrypoint signedClaim(addr : address,
name : string, name : string,
salt : int, salt : int,
sign : signature) : () = name_fee : int,
AENS.claim(addr, name, salt, signature = sign) sign : signature) : unit =
AENS.claim(addr, name, salt, name_fee, signature = sign)
// TODO: update() -- how to handle pointers? // TODO: update() -- how to handle pointers?
stateful entrypoint transfer(owner : address, stateful entrypoint transfer(owner : address,
new_owner : address, new_owner : address,
name_hash : hash) : () = name : string) : unit =
AENS.transfer(owner, new_owner, name_hash) AENS.transfer(owner, new_owner, name)
stateful entrypoint signedTransfer(owner : address, stateful entrypoint signedTransfer(owner : address,
new_owner : address, new_owner : address,
name_hash : hash, name : string,
sign : signature) : () = sign : signature) : unit =
AENS.transfer(owner, new_owner, name_hash, signature = sign) AENS.transfer(owner, new_owner, name, signature = sign)
stateful entrypoint revoke(owner : address, stateful entrypoint revoke(owner : address,
name_hash : hash) : () = name : string) : unit =
AENS.revoke(owner, name_hash) AENS.revoke(owner, name)
stateful entrypoint signedRevoke(owner : address, stateful entrypoint signedRevoke(owner : address,
name_hash : hash, name : string,
sign : signature) : () = sign : signature) : unit =
AENS.revoke(owner, name_hash, signature = sign) AENS.revoke(owner, name, signature = sign)
+1 -1
View File
@@ -24,7 +24,7 @@ contract AllSyntax =
if(valWithType(Map.empty) == None) if(valWithType(Map.empty) == None)
print(42 mod 10 * 5 / 3) print(42 mod 10 * 5 / 3)
function funWithType(x : int, y) : (int, list(int)) = (x, 0 :: [y] ++ []) function funWithType(x : int, y) : int * list(int) = (x, 0 :: [y] ++ [])
function funNoType() = function funNoType() =
let foo = (x, y : bool) => let foo = (x, y : bool) =>
if (! (y && x =< 0x0b || true)) [x] if (! (y && x =< 0x0b || true)) [x]
+1 -1
View File
@@ -1,6 +1,6 @@
contract Remote = contract Remote =
entrypoint foo : () => () entrypoint foo : () => unit
contract AddressLiterals = contract AddressLiterals =
entrypoint addr1() : bytes(32) = entrypoint addr1() : bytes(32) =
+4 -4
View File
@@ -3,8 +3,8 @@ contract Remote =
entrypoint up_to : (int) => list(int) entrypoint up_to : (int) => list(int)
entrypoint sum : (list(int)) => int entrypoint sum : (list(int)) => int
entrypoint some_string : () => string entrypoint some_string : () => string
entrypoint pair : (int, string) => (int, string) entrypoint pair : (int, string) => int * string
entrypoint squares : (int) => list((int, int)) entrypoint squares : (int) => list(int * int)
entrypoint filter_some : (list(option(int))) => list(int) entrypoint filter_some : (list(option(int))) => list(int)
entrypoint all_some : (list(option(int))) => option(list(int)) entrypoint all_some : (list(option(int))) => option(list(int))
@@ -47,7 +47,7 @@ contract ComplexTypes =
entrypoint pair(x : int, y : string) = (x, y) entrypoint pair(x : int, y : string) = (x, y)
entrypoint remote_pair(n : int, s : string) : (int, string) = entrypoint remote_pair(n : int, s : string) : int * string =
state.worker.pair(gas = 10000, n, s) state.worker.pair(gas = 10000, n, s)
entrypoint map(f, xs) = entrypoint map(f, xs) =
@@ -58,7 +58,7 @@ contract ComplexTypes =
entrypoint squares(n) = entrypoint squares(n) =
map((i) => (i, i * i), up_to(n)) map((i) => (i, i * i), up_to(n))
entrypoint remote_squares(n) : list((int, int)) = entrypoint remote_squares(n) : list(int * int) =
state.worker.squares(n) state.worker.squares(n)
// option types // option types
+1 -1
View File
@@ -1,5 +1,5 @@
contract Remote = contract Remote =
entrypoint dummy : () => () entrypoint dummy : () => unit
contract Events = contract Events =
+1 -1
View File
@@ -40,7 +40,7 @@ contract FunctionArguments =
entrypoint traffic_light(c : colour) = entrypoint traffic_light(c : colour) =
Red Red
entrypoint tuples(t : ()) = entrypoint tuples(t : unit) =
t t
entrypoint due(t : Chain.ttl) = entrypoint due(t : Chain.ttl) =
+2 -2
View File
@@ -93,8 +93,8 @@ contract Maps =
entrypoint tolist_state_s() = tolist_s(state.map_s) entrypoint tolist_state_s() = tolist_s(state.map_s)
// Map.from_list // Map.from_list
entrypoint fromlist_i(xs : list((int, pt))) = Map.from_list(xs) entrypoint fromlist_i(xs : list(int * pt)) = Map.from_list(xs)
entrypoint fromlist_s(xs : list((string, pt))) = Map.from_list(xs) entrypoint fromlist_s(xs : list(string * pt)) = Map.from_list(xs)
stateful entrypoint fromlist_state_i(xs) = put(state{ map_i = fromlist_i(xs) }) stateful entrypoint fromlist_state_i(xs) = put(state{ map_i = fromlist_i(xs) })
stateful entrypoint fromlist_state_s(xs) = put(state{ map_s = fromlist_s(xs) }) stateful entrypoint fromlist_state_s(xs) = put(state{ map_s = fromlist_s(xs) })
+1 -1
View File
@@ -3,7 +3,7 @@ namespace Lib =
entrypoint foo() = () entrypoint foo() = ()
contract Remote = contract Remote =
public function foo : () => () public function foo : () => unit
function bla() = () function bla() = ()
contract Contract = contract Contract =
+4 -4
View File
@@ -60,23 +60,23 @@ contract Oracles =
res res
stateful entrypoint extendOracle(o : oracle_id, stateful entrypoint extendOracle(o : oracle_id,
ttl : ttl) : () = ttl : ttl) : unit =
Oracle.extend(o, ttl) Oracle.extend(o, ttl)
stateful entrypoint signedExtendOracle(o : oracle_id, stateful entrypoint signedExtendOracle(o : oracle_id,
sign : signature, // Signed oracle address sign : signature, // Signed oracle address
ttl : ttl) : () = ttl : ttl) : unit =
Oracle.extend(o, signature = sign, ttl) Oracle.extend(o, signature = sign, ttl)
stateful entrypoint respond(o : oracle_id, stateful entrypoint respond(o : oracle_id,
q : query_id, q : query_id,
r : answer_t) : () = r : answer_t) : unit =
Oracle.respond(o, q, r) Oracle.respond(o, q, r)
stateful entrypoint signedRespond(o : oracle_id, stateful entrypoint signedRespond(o : oracle_id,
q : query_id, q : query_id,
sign : signature, sign : signature,
r : answer_t) : () = r : answer_t) : unit =
Oracle.respond(o, q, signature = sign, r) Oracle.respond(o, q, signature = sign, r)
entrypoint getQuestion(o : oracle_id, entrypoint getQuestion(o : oracle_id,
+1 -1
View File
@@ -21,7 +21,7 @@ contract Oracles =
function respond(o : oracle_id, function respond(o : oracle_id,
q : query_id, q : query_id,
sign : signature, sign : signature,
r : answer_t) : () = r : answer_t) : unit =
Oracle.respond(o, q, signature = sign, r) Oracle.respond(o, q, signature = sign, r)
+1 -1
View File
@@ -7,7 +7,7 @@ contract Remote2 =
contract Remote3 = contract Remote3 =
entrypoint get : () => int entrypoint get : () => int
entrypoint tick : () => () entrypoint tick : () => unit
contract RemoteCall = contract RemoteCall =
+1 -1
View File
@@ -1,7 +1,7 @@
contract Remote = contract Remote =
record rstate = { i : int, s : string, m : map(int, int) } record rstate = { i : int, s : string, m : map(int, int) }
entrypoint look_at : (rstate) => () entrypoint look_at : (rstate) => unit
entrypoint return_s : (bool) => string entrypoint return_s : (bool) => string
entrypoint return_m : (bool) => map(int, int) entrypoint return_m : (bool) => map(int, int)
entrypoint get : (rstate) => rstate entrypoint get : (rstate) => rstate
+2 -2
View File
@@ -1,6 +1,6 @@
contract Remote = contract Remote =
stateful entrypoint remote_spend : (address, int) => () stateful entrypoint remote_spend : (address, int) => unit
entrypoint remote_pure : int => int entrypoint remote_pure : int => int
contract Stateful = contract Stateful =
@@ -32,7 +32,7 @@ contract Stateful =
entrypoint ok4(a : address) = fail4(a) entrypoint ok4(a : address) = fail4(a)
// Lamdbas are checked at the construction site // Lamdbas are checked at the construction site
function fail5() : address => () = (a) => Chain.spend(a, 1000) function fail5() : address => unit = (a) => Chain.spend(a, 1000)
// .. so you can pass a stateful lambda to a non-stateful higher-order // .. so you can pass a stateful lambda to a non-stateful higher-order
// function: // function:
+2
View File
@@ -0,0 +1,2 @@
contract Stub =
entrypoint foo : (int) => int
+36
View File
@@ -0,0 +1,36 @@
contract TuplesMatch =
entrypoint tuplify3() = (t) => switch(t)
(x, y, z) => 3
entrypoint fst(p : int * string) =
switch(p)
(x, y) => x
entrypoint fst'(p : int * string) =
switch(p)
(x, _) => x
entrypoint snd(p : int * string) =
switch(p)
(x, y) => y
entrypoint snd'(p : int * string) =
switch(p)
(_, y) => y
entrypoint sum(p) =
switch(p)
(x, y) => x + y
entrypoint swap(p : int * string) =
switch(p)
(x, y) => (y, x)
entrypoint id(p : int * int * string) =
switch(p)
(x, y, z) => (x, y, z)
entrypoint nest(p : (int * int) * string) =
switch(p)
(xy, z) => switch(xy) (x, y) => (x, y, z)
entrypoint deep(p : (int * int) * (int * int)) =
switch(p)
((x, y), (z, w)) => (x, y, z, w)
entrypoint deep_sum(p : (int * int) * (int * int)) =
switch(p)
((x, y), (z, w)) => x + y + z + w
+1 -1
View File
@@ -8,7 +8,7 @@ contract VotingType =
function delegate : address => unit function delegate : address => unit
function vote : int => unit function vote : int => unit
function winnerName : unit => string function winnerName : unit => string
function currentTally : unit => list((string, int)) function currentTally : unit => list(string * int)
/* Contract implementation */ /* Contract implementation */
contract Voting = contract Voting =