Change get_state and set_state fcode primitives to take a register

This commit is contained in:
Ulf Norell 2019-09-23 14:51:15 +02:00
parent 99ecda4b7b
commit d0fdd06d66
2 changed files with 28 additions and 7 deletions

View File

@ -24,6 +24,8 @@
-type var_name() :: string(). -type var_name() :: string().
-type sophia_name() :: [string()]. -type sophia_name() :: [string()].
-type state_reg() :: pos_integer().
-type builtin() :: atom(). -type builtin() :: atom().
-type op() :: '+' | '-' | '*' | '/' | mod | '^' | '++' | '::' | -type op() :: '+' | '-' | '*' | '/' | mod | '^' | '++' | '::' |
@ -61,6 +63,8 @@
| {funcall, fexpr(), [fexpr()]} %% Call to unknown function | {funcall, fexpr(), [fexpr()]} %% Call to unknown function
| {closure, fun_name(), fexpr()} | {closure, fun_name(), fexpr()}
| {switch, fsplit()} | {switch, fsplit()}
| {set_state, state_reg(), fexpr()}
| {get_state, state_reg()}
%% The following (unapplied top-level functions/builtins and %% The following (unapplied top-level functions/builtins and
%% lambdas) are generated by the fcode compiler, but translated %% lambdas) are generated by the fcode compiler, but translated
%% to closures by the lambda lifter. %% to closures by the lambda lifter.
@ -910,6 +914,10 @@ op_builtins() ->
crypto_ecverify_secp256k1, crypto_ecrecover_secp256k1 crypto_ecverify_secp256k1, crypto_ecrecover_secp256k1
]. ].
builtin_to_fcode(set_state, [Val]) ->
{set_state, 1, Val};
builtin_to_fcode(get_state, []) ->
{get_state, 1};
builtin_to_fcode(require, [Cond, Msg]) -> builtin_to_fcode(require, [Cond, Msg]) ->
make_if(Cond, {tuple, []}, {builtin, abort, [Msg]}); make_if(Cond, {tuple, []}, {builtin, abort, [Msg]});
builtin_to_fcode(chain_event, [Event]) -> builtin_to_fcode(chain_event, [Event]) ->
@ -942,7 +950,7 @@ add_init_function(Env, Main, StateType, Funs0) ->
InitName = {entrypoint, <<"init">>}, InitName = {entrypoint, <<"init">>},
InitFun = #{ body := InitBody} = maps:get(InitName, Funs), InitFun = #{ body := InitBody} = maps:get(InitName, Funs),
Funs#{ InitName => InitFun#{ return => {tuple, []}, Funs#{ InitName => InitFun#{ return => {tuple, []},
body => {builtin, set_state, [InitBody]} } } body => builtin_to_fcode(set_state, [InitBody]) } }
end. end.
add_default_init_function(_Env, Main, StateType, Funs) -> add_default_init_function(_Env, Main, StateType, Funs) ->
@ -1072,6 +1080,8 @@ lambda_lift_expr(Expr) ->
{op, Op, As} -> {op, Op, lambda_lift_exprs(As)}; {op, Op, As} -> {op, Op, lambda_lift_exprs(As)};
{'let', X, A, B} -> {'let', X, lambda_lift_expr(A), lambda_lift_expr(B)}; {'let', X, A, B} -> {'let', X, lambda_lift_expr(A), lambda_lift_expr(B)};
{funcall, A, Bs} -> {funcall, lambda_lift_expr(A), lambda_lift_exprs(Bs)}; {funcall, A, Bs} -> {funcall, lambda_lift_expr(A), lambda_lift_exprs(Bs)};
{set_state, R, A} -> {set_state, R, lambda_lift_expr(A)};
{get_state, _} -> Expr;
{switch, S} -> {switch, lambda_lift_expr(S)}; {switch, S} -> {switch, lambda_lift_expr(S)};
{split, Type, X, Alts} -> {split, Type, X, lambda_lift_exprs(Alts)}; {split, Type, X, Alts} -> {split, Type, X, lambda_lift_exprs(Alts)};
{nosplit, A} -> {nosplit, lambda_lift_expr(A)}; {nosplit, A} -> {nosplit, lambda_lift_expr(A)};
@ -1236,7 +1246,7 @@ resolve_var(Env, Q) -> resolve_fun(Env, Q).
resolve_fun(#{ fun_env := Funs, builtins := Builtin }, Q) -> resolve_fun(#{ fun_env := Funs, builtins := Builtin }, Q) ->
case {maps:get(Q, Funs, not_found), maps:get(Q, Builtin, not_found)} of case {maps:get(Q, Funs, not_found), maps:get(Q, Builtin, not_found)} of
{not_found, not_found} -> internal_error({unbound_variable, Q}); {not_found, not_found} -> internal_error({unbound_variable, Q});
{_, {B, none}} -> {builtin, B, []}; {_, {B, none}} -> builtin_to_fcode(B, []);
{_, {B, Ar}} -> {builtin_u, B, Ar}; {_, {B, Ar}} -> {builtin_u, B, Ar};
{{Fun, Ar}, _} -> {def_u, Fun, Ar} {{Fun, Ar}, _} -> {def_u, Fun, Ar}
end. end.
@ -1301,6 +1311,8 @@ free_vars(Expr) ->
{op, _, As} -> free_vars(As); {op, _, As} -> free_vars(As);
{'let', X, A, B} -> free_vars([A, {lam, [X], B}]); {'let', X, A, B} -> free_vars([A, {lam, [X], B}]);
{funcall, A, Bs} -> free_vars([A | Bs]); {funcall, A, Bs} -> free_vars([A | Bs]);
{set_state, _, A} -> free_vars(A);
{get_state, _} -> [];
{lam, Xs, B} -> free_vars(B) -- lists:sort(Xs); {lam, Xs, B} -> free_vars(B) -- lists:sort(Xs);
{closure, _, A} -> free_vars(A); {closure, _, A} -> free_vars(A);
{switch, A} -> free_vars(A); {switch, A} -> free_vars(A);
@ -1330,6 +1342,8 @@ used_defs(Expr) ->
{op, _, As} -> used_defs(As); {op, _, As} -> used_defs(As);
{'let', _, A, B} -> used_defs([A, B]); {'let', _, A, B} -> used_defs([A, B]);
{funcall, A, Bs} -> used_defs([A | Bs]); {funcall, A, Bs} -> used_defs([A | Bs]);
{set_state, _, A} -> used_defs(A);
{get_state, _} -> [];
{lam, _, B} -> used_defs(B); {lam, _, B} -> used_defs(B);
{closure, F, A} -> lists:umerge([F], used_defs(A)); {closure, F, A} -> lists:umerge([F], used_defs(A));
{switch, A} -> used_defs(A); {switch, A} -> used_defs(A);
@ -1372,6 +1386,8 @@ rename(Ren, Expr) ->
{set_proj, R, I, E} -> {set_proj, rename(Ren, R), I, rename(Ren, E)}; {set_proj, R, I, E} -> {set_proj, rename(Ren, R), I, rename(Ren, E)};
{op, Op, Es} -> {op, Op, [rename(Ren, E) || E <- Es]}; {op, Op, Es} -> {op, Op, [rename(Ren, E) || E <- Es]};
{funcall, Fun, Es} -> {funcall, rename(Ren, Fun), [rename(Ren, E) || E <- Es]}; {funcall, Fun, Es} -> {funcall, rename(Ren, Fun), [rename(Ren, E) || E <- Es]};
{set_state, R, E} -> {set_state, R, rename(Ren, E)};
{get_state, _} -> Expr;
{closure, F, Env} -> {closure, F, rename(Ren, Env)}; {closure, F, Env} -> {closure, F, rename(Ren, Env)};
{switch, Split} -> {switch, rename_split(Ren, Split)}; {switch, Split} -> {switch, rename_split(Ren, Split)};
{lam, Xs, B} -> {lam, Xs, B} ->
@ -1595,6 +1611,10 @@ pp_fexpr({remote, ArgsT, RetT, Ct, Fun, As}) ->
pp_call(pp_parens(pp_beside([pp_fexpr(Ct), pp_text("."), pp_fun_name(Fun), pp_text(" : "), pp_ftype({function, ArgsT, RetT})])), As); pp_call(pp_parens(pp_beside([pp_fexpr(Ct), pp_text("."), pp_fun_name(Fun), pp_text(" : "), pp_ftype({function, ArgsT, RetT})])), As);
pp_fexpr({funcall, Fun, As}) -> pp_fexpr({funcall, Fun, As}) ->
pp_call(pp_fexpr(Fun), As); pp_call(pp_fexpr(Fun), As);
pp_fexpr({set_state, R, A}) ->
pp_call(pp_text("set_state"), [{lit, {int, R}}, A]);
pp_fexpr({get_state, R}) ->
pp_call(pp_text("get_state"), [{lit, {int, R}}]);
pp_fexpr({switch, Split}) -> pp_split(Split). pp_fexpr({switch, Split}) -> pp_split(Split).
pp_call(Fun, Args) -> pp_call(Fun, Args) ->

View File

@ -298,6 +298,12 @@ to_scode(Env, {remote, ArgsT, RetT, Ct, Fun, [Gas, Value | Args]}) ->
call_to_scode(Env, Call, [Ct, Value, Gas | Args]) call_to_scode(Env, Call, [Ct, Value, Gas | Args])
end; end;
to_scode(_Env, {get_state, Reg}) ->
[push(?s(Reg))];
to_scode(Env, {set_state, Reg, Val}) ->
call_to_scode(Env, [aeb_fate_ops:store(?s(Reg), ?a),
tuple(0)], [Val]);
to_scode(Env, {closure, Fun, FVs}) -> to_scode(Env, {closure, Fun, FVs}) ->
to_scode(Env, {tuple, [{lit, {string, make_function_id(Fun)}}, FVs]}); to_scode(Env, {tuple, [{lit, {string, make_function_id(Fun)}}, FVs]});
@ -420,11 +426,6 @@ call_to_scode(Env, CallCode, Args) ->
[[to_scode(notail(Env), A) || A <- lists:reverse(Args)], [[to_scode(notail(Env), A) || A <- lists:reverse(Args)],
CallCode]. CallCode].
builtin_to_scode(_Env, get_state, []) ->
[push(?s(1))];
builtin_to_scode(Env, set_state, [_] = Args) ->
call_to_scode(Env, [aeb_fate_ops:store(?s(1), ?a),
tuple(0)], Args);
builtin_to_scode(Env, chain_event, Args) -> builtin_to_scode(Env, chain_event, Args) ->
call_to_scode(Env, [erlang:apply(aeb_fate_ops, log, lists:duplicate(length(Args), ?a)), call_to_scode(Env, [erlang:apply(aeb_fate_ops, log, lists:duplicate(length(Args), ?a)),
tuple(0)], Args); tuple(0)], Args);