Compile events to FATE

This commit is contained in:
Ulf Norell
2019-06-25 14:54:01 +02:00
parent a3efaf71a7
commit 0cf6a52b26
4 changed files with 64 additions and 21 deletions
+52 -14
View File
@@ -16,11 +16,11 @@
-type option() :: term().
-type attribute() :: stateful | pure.
-type attribute() :: stateful | pure | private.
-type fun_name() :: {entrypoint, binary()}
| {local_fun, [string()]}
| init.
| init | event.
-type var_name() :: string().
-type sophia_name() :: [string()].
@@ -127,14 +127,15 @@
| {namespace, string()}
| {abstract_contract, string()}.
-type env() :: #{ type_env := type_env(),
fun_env := fun_env(),
con_env := con_env(),
builtins := builtins(),
options := [option()],
context => context(),
vars => [var_name()],
functions := #{ fun_name() => fun_def() } }.
-type env() :: #{ type_env := type_env(),
fun_env := fun_env(),
con_env := con_env(),
event_type := aeso_syntax:typedef(),
builtins := builtins(),
options := [option()],
context => context(),
vars => [var_name()],
functions := #{ fun_name() => fun_def() } }.
%% -- Entrypoint -------------------------------------------------------------
@@ -229,7 +230,7 @@ to_fcode(Env, [{contract, _, {con, _, Main}, Decls}]) ->
MainEnv = Env#{ context => {main_contract, Main},
builtins => Builtins#{[Main, "state"] => {get_state, none},
[Main, "put"] => {set_state, 1},
[Main, "Chain", "event"] => {event, 1}} },
[Main, "Chain", "event"] => {chain_event, 1}} },
#{ functions := Funs } = Env1 =
decls_to_fcode(MainEnv, Decls),
StateType = lookup_type(Env1, [Main, "state"], [], {tuple, []}),
@@ -237,7 +238,7 @@ to_fcode(Env, [{contract, _, {con, _, Main}, Decls}]) ->
#{ contract_name => Main,
state_type => StateType,
event_type => EventType,
functions => Funs };
functions => add_event_function(Env1, EventType, Funs) };
to_fcode(Env, [{contract, _, {con, _, Con}, Decls} | Code]) ->
Env1 = decls_to_fcode(Env#{ context => {abstract_contract, Con} }, Decls),
to_fcode(Env1, Code);
@@ -303,7 +304,11 @@ typedef_to_fcode(Env, {id, _, Name}, Xs, Def) ->
_ -> #{}
end,
Env1 = bind_constructors(Env, Constructors),
bind_type(Env1, Q, FDef).
Env2 = case Name of
"event" -> Env1#{ event_type => Def };
_ -> Env1
end,
bind_type(Env2, Q, FDef).
-spec type_to_fcode(env(), aeso_syntax:type()) -> ftype().
type_to_fcode(Env, Type) ->
@@ -788,6 +793,8 @@ op_builtins() ->
builtin_to_fcode(require, [Cond, Msg]) ->
make_if(Cond, {tuple, []}, {builtin, abort, [Msg]});
builtin_to_fcode(chain_event, [Event]) ->
{def, event, [Event]};
builtin_to_fcode(map_delete, [Key, Map]) ->
{op, map_delete, [Map, Key]};
builtin_to_fcode(map_member, [Key, Map]) ->
@@ -806,6 +813,36 @@ builtin_to_fcode(Builtin, Args) ->
false -> {builtin, Builtin, Args}
end.
%% -- Event function --
add_event_function(_Env, none, Funs) -> Funs;
add_event_function(Env, EventFType, Funs) ->
Funs#{ event => event_function(Env, EventFType) }.
event_function(_Env = #{event_type := {variant_t, EventCons}}, EventType = {variant, FCons}) ->
Cons = [ {Name, I - 1, proplists:get_value(indices, Ann)}
|| {I, {constr_t, Ann, {con, _, Name}, _}} <- indexed(EventCons) ],
Arities = [length(Ts) || Ts <- FCons],
io:format("Cons = ~p\nEventFType = ~p\n", [Cons, EventType]),
Case = fun({Name, Tag, Ixs}) ->
%% TODO: precompute (needs dependency)
Hash = {op, crypto_sha3, [{lit, {string, list_to_binary(Name)}}]},
Vars = [ "arg" ++ integer_to_list(I) || I <- lists:seq(1, length(Ixs)) ],
IVars = lists:zip(Ixs, Vars),
Payload =
case [ V || {notindexed, V} <- IVars ] of
[] -> {lit, {string, <<>>}};
[V] -> {var, V}
end,
Indices = [ {var, V} || {indexed, V} <- IVars ],
Body = {builtin, chain_event, [Payload, Hash | Indices]},
{'case', {con, Arities, Tag, Vars}, {nosplit, Body}}
end,
#{ attrs => [stateful, private],
args => [{"e", EventType}],
return => {tuple, []},
body => {switch, {split, EventType, "e", lists:map(Case, Cons)}} }.
%% -- Lambda lifting ---------------------------------------------------------
%% The expr_to_fcode compiler lambda expressions to {lam, Xs, Body}, but in
%% FATE we can only call top-level functions, so we need to lift the lambda to
@@ -1237,7 +1274,8 @@ pp_fun(Name, #{ args := Args, return := Return, body := Body }) ->
pp_text(" : "), pp_ftype(Return), pp_text(" =")]),
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({entrypoint, E}) -> pp_text(binary_to_list(E));
pp_fun_name({local_fun, Q}) -> pp_text(string:join(Q, ".")).