Compile builtins
This commit is contained in:
parent
6f17477c72
commit
1f40d2a321
@ -24,9 +24,13 @@
|
||||
-type var_name() :: string().
|
||||
-type sophia_name() :: [string()].
|
||||
|
||||
-type binop() :: '+' | '-' | '*' | '/' | mod | '^' | '++' | '::' |
|
||||
'<' | '>' | '=<' | '>=' | '==' | '!='.
|
||||
-type unop() :: '!'.
|
||||
-type builtin() :: atom().
|
||||
|
||||
-type op() :: '+' | '-' | '*' | '/' | mod | '^' | '++' | '::' |
|
||||
'<' | '>' | '=<' | '>=' | '==' | '!=' | '!' |
|
||||
map_from_list | map_to_list | map_delete | map_member | map_size |
|
||||
string_length | string_concat | bits_set | bits_clear | bits_test |
|
||||
bits_sum | bits_intersection | bits_union | bits_difference.
|
||||
|
||||
-type fexpr() :: {int, integer()}
|
||||
| {string, binary()}
|
||||
@ -38,6 +42,8 @@
|
||||
| nil
|
||||
| {var, var_name()}
|
||||
| {def, fun_name()}
|
||||
| {builtin, builtin(), non_neg_integer() | none} %% Unapplied builtin
|
||||
| {builtin, builtin(), [fexpr()]}
|
||||
| {con, arities(), tag(), [fexpr()]}
|
||||
| {tuple, [fexpr()]}
|
||||
| {proj, fexpr(), integer()}
|
||||
@ -46,8 +52,7 @@
|
||||
| {map_set, fexpr(), fexpr(), fexpr()} % map, key, val
|
||||
| {map_get, fexpr(), fexpr()} % map, key
|
||||
| {map_get, fexpr(), fexpr(), fexpr()} % map, key, default
|
||||
| {op, binop(), fexpr(), fexpr()}
|
||||
| {op, unop(), fexpr()}
|
||||
| {op, op(), [fexpr()]}
|
||||
| {'let', var_name(), fexpr(), fexpr()}
|
||||
| {funcall, fexpr(), [fexpr()]}
|
||||
| {switch, fsplit()}.
|
||||
@ -104,6 +109,7 @@
|
||||
-type type_env() :: #{ sophia_name() => type_def() }.
|
||||
-type fun_env() :: #{ sophia_name() => fun_name() }.
|
||||
-type con_env() :: #{ sophia_name() => con_tag() }.
|
||||
-type builtins() :: #{ sophia_name() => {builtin(), non_neg_integer() | none} }.
|
||||
|
||||
-type context() :: {main_contract, string()}
|
||||
| {namespace, string()}
|
||||
@ -112,6 +118,7 @@
|
||||
-type env() :: #{ type_env := type_env(),
|
||||
fun_env := fun_env(),
|
||||
con_env := con_env(),
|
||||
builtins := builtins(),
|
||||
options := [option()],
|
||||
context => context(),
|
||||
vars => [var_name()],
|
||||
@ -130,13 +137,47 @@ ast_to_fcode(Code, Options) ->
|
||||
-spec init_env([option()]) -> env().
|
||||
init_env(Options) ->
|
||||
#{ type_env => init_type_env(),
|
||||
fun_env => #{}, %% TODO: builtin functions here?
|
||||
fun_env => #{},
|
||||
builtins => builtins(),
|
||||
con_env => #{["None"] => #con_tag{ tag = 0, arities = [0, 1] },
|
||||
["Some"] => #con_tag{ tag = 1, arities = [0, 1] }
|
||||
["Some"] => #con_tag{ tag = 1, arities = [0, 1] },
|
||||
["RelativeTTL"] => #con_tag{ tag = 0, arities = [1, 1] },
|
||||
["FixedTTL"] => #con_tag{ tag = 1, arities = [1, 1] }
|
||||
},
|
||||
options => Options,
|
||||
functions => #{} }.
|
||||
|
||||
-spec builtins() -> builtins().
|
||||
builtins() ->
|
||||
MkName = fun(NS, Fun) ->
|
||||
list_to_atom(string:to_lower(string:join(NS ++ [Fun], "_")))
|
||||
end,
|
||||
Scopes = [{[], [{"abort", 1}]},
|
||||
{["Chain"], [{"spend", 2}, {"balance", 1}, {"block_hash", 1}, {"coinbase", none},
|
||||
{"timestamp", none}, {"block_height", none}, {"difficulty", none},
|
||||
{"gas_limit", none}]},
|
||||
{["Contract"], [{"address", none}, {"balance", none}]},
|
||||
{["Call"], [{"origin", none}, {"caller", none}, {"value", none}, {"gas_price", none},
|
||||
{"gas_left", 0}]},
|
||||
{["Oracle"], [{"register", 4}, {"query_fee", 1}, {"query", 5}, {"get_question", 2},
|
||||
{"respond", 4}, {"extend", 3}, {"get_answer", 2}]},
|
||||
{["AENS"], [{"resolve", 2}, {"preclaim", 3}, {"claim", 4}, {"transfer", 4},
|
||||
{"revoke", 3}]},
|
||||
{["Map"], [{"from_list", 1}, {"to_list", 1}, {"lookup", 2},
|
||||
{"lookup_default", 3}, {"delete", 2}, {"member", 2}, {"size", 1}]},
|
||||
{["Crypto"], [{"ecverify", 3}, {"ecverify_secp256k1", 3}, {"sha3", 1},
|
||||
{"sha256", 1}, {"blake2b", 1}]},
|
||||
{["Auth"], [{"tx_hash", none}]},
|
||||
{["String"], [{"length", 1}, {"concat", 2}, {"sha3", 1}, {"sha256", 1}, {"blake2b", 1}]},
|
||||
{["Bits"], [{"set", 2}, {"clear", 2}, {"test", 2}, {"sum", 1}, {"intersection", 2},
|
||||
{"union", 2}, {"difference", 2}, {"none", none}, {"all", none}]},
|
||||
{["Int"], [{"to_str", 1}]},
|
||||
{["Address"], [{"to_str", 1}]}
|
||||
],
|
||||
maps:from_list([ {NS ++ [Fun], {MkName(NS, Fun), Arity}}
|
||||
|| {NS, Funs} <- Scopes,
|
||||
{Fun, Arity} <- Funs ]).
|
||||
|
||||
-define(type(T), fun([]) -> T end).
|
||||
-define(type(X, T), fun([X]) -> T end).
|
||||
-define(type(X, Y, T), fun([X, Y]) -> T end).
|
||||
@ -333,7 +374,7 @@ expr_to_fcode(Env, {record_t, FieldTypes}, {record, _Ann, Rec, Fields}) ->
|
||||
|
||||
%% Lists
|
||||
expr_to_fcode(Env, _Type, {list, _, Es}) ->
|
||||
lists:foldr(fun(E, L) -> {op, '::', expr_to_fcode(Env, E), L} end,
|
||||
lists:foldr(fun(E, L) -> {op, '::', [expr_to_fcode(Env, E), L]} end,
|
||||
nil, Es);
|
||||
|
||||
%% Conditionals
|
||||
@ -372,16 +413,25 @@ expr_to_fcode(Env, _Type, Expr = {app, _, {Op, _}, [_, _]}) when Op == '&&'; Op
|
||||
Tree = expr_to_decision_tree(Env, Expr),
|
||||
decision_tree_to_fcode(Tree);
|
||||
expr_to_fcode(Env, _Type, {app, _Ann, {Op, _}, [A, B]}) when is_atom(Op) ->
|
||||
{op, Op, expr_to_fcode(Env, A), expr_to_fcode(Env, B)};
|
||||
{op, Op, [expr_to_fcode(Env, A), expr_to_fcode(Env, B)]};
|
||||
expr_to_fcode(Env, _Type, {app, _Ann, {Op, _}, [A]}) when is_atom(Op) ->
|
||||
case Op of
|
||||
'-' -> {op, '-', {int, 0}, expr_to_fcode(Env, A)};
|
||||
'!' -> {op, '!', expr_to_fcode(Env, A)}
|
||||
'-' -> {op, '-', [{int, 0}, expr_to_fcode(Env, A)]};
|
||||
'!' -> {op, '!', [expr_to_fcode(Env, A)]}
|
||||
end;
|
||||
|
||||
%% Function calls
|
||||
expr_to_fcode(Env, _Type, {app, _Ann, Fun, Args}) ->
|
||||
{funcall, expr_to_fcode(Env, Fun), [expr_to_fcode(Env, Arg) || Arg <- Args]};
|
||||
expr_to_fcode(Env, _Type, {app, _Ann, Fun = {typed, _, _, {fun_t, _, NamedArgsT, _, _}}, Args}) ->
|
||||
Args1 = get_named_args(NamedArgsT, Args),
|
||||
FArgs = [expr_to_fcode(Env, Arg) || Arg <- Args1],
|
||||
case expr_to_fcode(Env, Fun) of
|
||||
{builtin, B, Ar} when is_integer(Ar) ->
|
||||
case length(FArgs) of
|
||||
N when N == Ar -> builtin_to_fcode(B, FArgs);
|
||||
N when N < Ar -> error({todo, eta_expand, B, FArgs})
|
||||
end;
|
||||
FFun -> {funcall, FFun, FArgs}
|
||||
end;
|
||||
|
||||
%% Maps
|
||||
expr_to_fcode(_Env, _Type, {map, _, []}) ->
|
||||
@ -628,6 +678,24 @@ stmts_to_fcode(Env, [{letval, _, {typed, _, {id, _, X}, _}, _, Expr} | Stmts]) -
|
||||
stmts_to_fcode(Env, [Expr]) ->
|
||||
expr_to_fcode(Env, Expr).
|
||||
|
||||
%% -- Builtins --
|
||||
|
||||
op_builtins() ->
|
||||
[map_from_list, map_to_list, map_delete, map_member, map_size,
|
||||
string_length, string_concat, string_sha3, string_sha256, string_blake2b,
|
||||
bits_set, bits_clear, bits_test, bits_sum, bits_intersection, bits_union,
|
||||
bits_difference, int_to_str, address_to_str].
|
||||
|
||||
builtin_to_fcode(map_lookup, [Key, Map]) ->
|
||||
{map_get, Map, Key};
|
||||
builtin_to_fcode(map_lookup_default, [Key, Map, Def]) ->
|
||||
{map_get, Map, Key, Def};
|
||||
builtin_to_fcode(Builtin, Args) ->
|
||||
case lists:member(Builtin, op_builtins()) of
|
||||
true -> {op, Builtin, Args};
|
||||
false -> {builtin, Builtin, Args}
|
||||
end.
|
||||
|
||||
%% -- Optimisations ----------------------------------------------------------
|
||||
|
||||
%% - Deadcode elimination
|
||||
@ -739,9 +807,10 @@ resolve_var(#{ vars := Vars } = Env, [X]) ->
|
||||
end;
|
||||
resolve_var(Env, Q) -> resolve_fun(Env, Q).
|
||||
|
||||
resolve_fun(#{ fun_env := Funs }, Q) ->
|
||||
case maps:get(Q, Funs, not_found) of
|
||||
resolve_fun(#{ fun_env := Funs, builtins := Builtin }, Q) ->
|
||||
case maps:get(Q, maps:merge(Funs, Builtin), not_found) of
|
||||
not_found -> fcode_error({unbound_variable, Q});
|
||||
{B, Ar} -> {builtin, B, Ar};
|
||||
Fun -> {def, Fun}
|
||||
end.
|
||||
|
||||
@ -768,6 +837,19 @@ pat_vars({tuple, 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)].
|
||||
|
||||
get_named_args(NamedArgsT, Args) ->
|
||||
IsNamed = fun({named_arg, _, _, _}) -> true;
|
||||
(_) -> false end,
|
||||
{Named, NotNamed} = lists:partition(IsNamed, Args),
|
||||
NamedArgs = [get_named_arg(NamedArg, Named) || NamedArg <- NamedArgsT],
|
||||
NamedArgs ++ NotNamed.
|
||||
|
||||
get_named_arg({named_arg_t, _, {id, _, Name}, _, Default}, Args) ->
|
||||
case [ Val || {named_arg, _, {id, _, X}, Val} <- Args, X == Name ] of
|
||||
[Val] -> Val;
|
||||
[] -> Default
|
||||
end.
|
||||
|
||||
%% -- Renaming --
|
||||
|
||||
-spec rename([{var_name(), var_name()}], fexpr()) -> fexpr().
|
||||
@ -787,8 +869,7 @@ rename(Ren, Expr) ->
|
||||
{tuple, Es} -> {tuple, [rename(Ren, E) || E <- Es]};
|
||||
{proj, E, I} -> {proj, rename(Ren, E), I};
|
||||
{set_proj, R, I, E} -> {set_proj, rename(Ren, R), I, rename(Ren, E)};
|
||||
{op, Op, E1, E2} -> {op, Op, rename(Ren, E1), rename(Ren, E2)};
|
||||
{op, Op, E} -> {op, Op, rename(Ren, E)};
|
||||
{op, Op, Es} -> {op, Op, [rename(Ren, E) || E <- Es]};
|
||||
{funcall, Fun, Es} -> {funcall, Fun, [rename(Ren, E) || E <- Es]};
|
||||
{'let', X, E, Body} ->
|
||||
{Z, Ren1} = rename_binding(Ren, X),
|
||||
@ -936,7 +1017,6 @@ pp_fexpr(nil) ->
|
||||
pp_fexpr({var, X}) -> pp_text(X);
|
||||
pp_fexpr({def, {entrypoint, E}}) -> pp_text(E);
|
||||
pp_fexpr({def, {local_fun, Q}}) -> pp_text(string:join(Q, "."));
|
||||
pp_fexpr({def, {builtin, B}}) -> pp_text(B);
|
||||
pp_fexpr({con, _, I, []}) ->
|
||||
pp_beside(pp_text("C"), pp_text(I));
|
||||
pp_fexpr({con, _, I, Es}) ->
|
||||
@ -948,17 +1028,33 @@ pp_fexpr({proj, E, I}) ->
|
||||
pp_beside([pp_fexpr(E), pp_text("."), pp_text(I)]);
|
||||
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_fexpr({op, Op, A, B}) ->
|
||||
pp_parens(pp_par([pp_fexpr(A), pp_text(Op), pp_fexpr(B)]));
|
||||
pp_fexpr({op, Op, A}) ->
|
||||
pp_parens(pp_par([pp_text(Op), pp_fexpr(A)]));
|
||||
pp_fexpr({op, Op, [A, B] = Args}) ->
|
||||
case is_infix(Op) of
|
||||
false -> pp_call(pp_text(Op), Args);
|
||||
true -> pp_parens(pp_par([pp_fexpr(A), pp_text(Op), pp_fexpr(B)]))
|
||||
end;
|
||||
pp_fexpr({op, Op, [A] = Args}) ->
|
||||
case is_infix(Op) of
|
||||
false -> pp_call(pp_text(Op), Args);
|
||||
true -> pp_parens(pp_par([pp_text(Op), pp_fexpr(A)]))
|
||||
end;
|
||||
pp_fexpr({op, Op, As}) ->
|
||||
pp_beside(pp_text(Op), pp_fexpr({tuple, As}));
|
||||
pp_fexpr({'let', X, A, B}) ->
|
||||
pp_par([pp_beside([pp_text("let "), pp_text(X), pp_text(" = "), pp_fexpr(A), pp_text(" in")]),
|
||||
pp_fexpr(B)]);
|
||||
pp_fexpr({builtin, B, none}) -> pp_text(B);
|
||||
pp_fexpr({builtin, B, N}) when is_integer(N) ->
|
||||
pp_beside([pp_text(B), pp_text("/"), pp_text(N)]);
|
||||
pp_fexpr({builtin, B, As}) when is_list(As) ->
|
||||
pp_call(pp_text(B), As);
|
||||
pp_fexpr({funcall, Fun, As}) ->
|
||||
pp_beside(pp_fexpr(Fun), pp_fexpr({tuple, As}));
|
||||
pp_call(pp_fexpr(Fun), As);
|
||||
pp_fexpr({switch, Split}) -> pp_split(Split).
|
||||
|
||||
pp_call(Fun, Args) ->
|
||||
pp_beside(Fun, pp_fexpr({tuple, Args})).
|
||||
|
||||
pp_ftype(T) when is_atom(T) -> pp_text(T);
|
||||
pp_ftype({tuple, Ts}) ->
|
||||
pp_parens(pp_par(pp_punctuate(pp_text(","), [pp_ftype(T) || T <- Ts])));
|
||||
@ -982,8 +1078,12 @@ pp_case({'case', Pat, Split}) ->
|
||||
prettypr:nest(2, pp_split(Split))]).
|
||||
|
||||
pp_pat({tuple, Xs}) -> pp_fexpr({tuple, [{var, X} || X <- Xs]});
|
||||
pp_pat({'::', X, Xs}) -> pp_fexpr({op, '::', {var, X}, {var, Xs}});
|
||||
pp_pat({'::', X, Xs}) -> pp_fexpr({op, '::', [{var, X}, {var, Xs}]});
|
||||
pp_pat({con, As, I, Xs}) -> pp_fexpr({con, As, I, [{var, X} || X <- Xs]});
|
||||
pp_pat({var, X}) -> pp_fexpr({var, X});
|
||||
pp_pat(Pat) -> pp_fexpr(Pat).
|
||||
|
||||
is_infix(Op) ->
|
||||
C = hd(atom_to_list(Op)),
|
||||
C < $a orelse C > $z.
|
||||
|
||||
|
@ -223,31 +223,20 @@ to_scode(Env, {set_proj, R, I, E}) ->
|
||||
to_scode(notail(Env), R),
|
||||
aeb_fate_code:setelement(?a, ?i(I), ?a, ?a)];
|
||||
|
||||
to_scode(Env, {op, Op, A, B}) ->
|
||||
[ to_scode(notail(Env), B),
|
||||
to_scode(notail(Env), A),
|
||||
binop_to_scode(Op) ];
|
||||
to_scode(Env, {op, Op, A}) ->
|
||||
[ to_scode(notail(Env), A),
|
||||
unop_to_scode(Op) ];
|
||||
to_scode(Env, {op, Op, Args}) ->
|
||||
call_to_scode(Env, op_to_scode(Op), Args);
|
||||
|
||||
%% Maps
|
||||
to_scode(_Env, map_empty) ->
|
||||
[aeb_fate_code:map_empty(?a)];
|
||||
to_scode(Env, {map_set, Map, Key, Val}) ->
|
||||
[to_scode(notail(Env), Val),
|
||||
to_scode(notail(Env), Key),
|
||||
to_scode(notail(Env), Map),
|
||||
aeb_fate_code:map_update(?a, ?a, ?a, ?a)];
|
||||
call_to_scode(Env, aeb_fate_code:map_update(?a, ?a, ?a, ?a),
|
||||
[Map, Key, Val]);
|
||||
to_scode(Env, {map_get, Map, Key}) ->
|
||||
[to_scode(notail(Env), Key),
|
||||
to_scode(notail(Env), Map),
|
||||
aeb_fate_code:map_lookup(?a, ?a, ?a)];
|
||||
call_to_scode(Env, aeb_fate_code:map_lookup(?a, ?a, ?a), [Map, Key]);
|
||||
to_scode(Env, {map_get, Map, Key, Default}) ->
|
||||
[to_scode(notail(Env), Default),
|
||||
to_scode(notail(Env), Key),
|
||||
to_scode(notail(Env), Map),
|
||||
aeb_fate_code:map_lookup(?a, ?a, ?a, ?a)];
|
||||
call_to_scode(Env, aeb_fate_code:map_lookup(?a, ?a, ?a, ?a),
|
||||
[Map, Key, Default]);
|
||||
|
||||
to_scode(Env, {'let', X, {var, Y}, Body}) ->
|
||||
Env1 = bind_var(X, lookup_var(Env, Y), Env),
|
||||
@ -276,6 +265,9 @@ to_scode(Env, {funcall, Fun, Args}) ->
|
||||
to_scode(Env, {switch, Case}) ->
|
||||
split_to_scode(Env, Case);
|
||||
|
||||
to_scode(Env, {builtin, B, Args}) ->
|
||||
builtin_to_scode(Env, B, Args);
|
||||
|
||||
to_scode(_Env, Icode) -> ?TODO(Icode).
|
||||
|
||||
split_to_scode(Env, {nosplit, Expr}) ->
|
||||
@ -387,24 +379,123 @@ match_tuple(Env, I, Elem, Arg, [X | Xs]) ->
|
||||
match_tuple(Env, _, _, _, []) ->
|
||||
{[], Env}.
|
||||
|
||||
%% -- Builtins --
|
||||
|
||||
call_to_scode(Env, CallCode, Args) ->
|
||||
[[to_scode(notail(Env), A) || A <- lists:reverse(Args)],
|
||||
CallCode].
|
||||
|
||||
builtin_to_scode(_Env, bits_none, none) ->
|
||||
[aeb_fate_code:bits_none(?a)];
|
||||
builtin_to_scode(_Env, bits_all, none) ->
|
||||
[aeb_fate_code:bits_all(?a)];
|
||||
builtin_to_scode(Env, abort, [_] = Args) ->
|
||||
call_to_scode(Env, aeb_fate_code:abort(?a), Args);
|
||||
builtin_to_scode(Env, chain_spend, [_, _] = Args) ->
|
||||
call_to_scode(Env, [aeb_fate_code:spend(?a, ?a),
|
||||
aeb_fate_code:tuple(0)], Args);
|
||||
builtin_to_scode(Env, chain_balance, [_] = Args) ->
|
||||
call_to_scode(Env, aeb_fate_code:balance_other(?a, ?a), Args);
|
||||
builtin_to_scode(_Env, chain_block_hash, [{builtin, chain_block_height, none}]) ->
|
||||
[aeb_fate_code:blockhash(?a)];
|
||||
builtin_to_scode(_Env, chain_block_hash, [_]) ->
|
||||
?TODO(fate_block_hash_at_height_instruction);
|
||||
builtin_to_scode(_Env, chain_coinbase, none) ->
|
||||
[aeb_fate_code:beneficiary(?a)];
|
||||
builtin_to_scode(_Env, chain_timestamp, none) ->
|
||||
[aeb_fate_code:timestamp(?a)];
|
||||
builtin_to_scode(_Env, chain_block_height, none) ->
|
||||
[aeb_fate_code:generation(?a)];
|
||||
builtin_to_scode(_Env, chain_difficulty, none) ->
|
||||
[aeb_fate_code:difficulty(?a)];
|
||||
builtin_to_scode(_Env, chain_gas_limit, none) ->
|
||||
[aeb_fate_code:gaslimit(?a)];
|
||||
builtin_to_scode(_Env, contract_balance, none) ->
|
||||
[aeb_fate_code:balance(?a)];
|
||||
builtin_to_scode(_Env, contract_address, none) ->
|
||||
[aeb_fate_code:address(?a)];
|
||||
builtin_to_scode(_Env, call_origin, none) ->
|
||||
[aeb_fate_code:origin(?a)];
|
||||
builtin_to_scode(_Env, call_caller, none) ->
|
||||
[aeb_fate_code:caller(?a)];
|
||||
builtin_to_scode(_Env, call_value, none) ->
|
||||
?TODO(fate_call_value_instruction);
|
||||
builtin_to_scode(_Env, call_gas_price, none) ->
|
||||
[aeb_fate_code:gasprice(?a)];
|
||||
builtin_to_scode(_Env, call_gas_left, []) ->
|
||||
[aeb_fate_code:gas(?a)];
|
||||
builtin_to_scode(_Env, oracle_register, [_, _, _, _] = _Args) ->
|
||||
?TODO(fate_oracle_register_instruction);
|
||||
builtin_to_scode(_Env, oracle_query_fee, [_] = _Args) ->
|
||||
?TODO(fate_oracle_query_fee_instruction);
|
||||
builtin_to_scode(_Env, oracle_query, [_, _, _, _, _] = _Args) ->
|
||||
?TODO(fate_oracle_query_instruction);
|
||||
builtin_to_scode(_Env, oracle_get_question, [_, _] = _Args) ->
|
||||
?TODO(fate_oracle_get_question_instruction);
|
||||
builtin_to_scode(_Env, oracle_respond, [_, _, _, _] = _Args) ->
|
||||
?TODO(fate_oracle_respond_instruction);
|
||||
builtin_to_scode(_Env, oracle_extend, [_, _, _] = _Args) ->
|
||||
?TODO(fate_oracle_extend_instruction);
|
||||
builtin_to_scode(_Env, oracle_get_answer, [_, _] = _Args) ->
|
||||
?TODO(fate_oracle_get_answer_instruction);
|
||||
builtin_to_scode(_Env, aens_resolve, [_, _] = _Args) ->
|
||||
?TODO(fate_aens_resolve_instruction);
|
||||
builtin_to_scode(_Env, aens_preclaim, [_, _, _] = _Args) ->
|
||||
?TODO(fate_aens_preclaim_instruction);
|
||||
builtin_to_scode(_Env, aens_claim, [_, _, _, _] = _Args) ->
|
||||
?TODO(fate_aens_claim_instruction);
|
||||
builtin_to_scode(_Env, aens_transfer, [_, _, _, _] = _Args) ->
|
||||
?TODO(fate_aens_transfer_instruction);
|
||||
builtin_to_scode(_Env, aens_revoke, [_, _, _] = _Args) ->
|
||||
?TODO(fate_aens_revoke_instruction);
|
||||
builtin_to_scode(_Env, crypto_ecverify, [_, _, _] = _Args) ->
|
||||
?TODO(fate_crypto_ecverify_instruction);
|
||||
builtin_to_scode(_Env, crypto_ecverify_secp256k1, [_, _, _] = _Args) ->
|
||||
?TODO(fate_crypto_ecverify_secp256k1_instruction);
|
||||
builtin_to_scode(_Env, crypto_sha3, [_] = _Args) ->
|
||||
?TODO(fate_crypto_sha3_instruction);
|
||||
builtin_to_scode(_Env, crypto_sha256, [_] = _Args) ->
|
||||
?TODO(fate_crypto_sha256_instruction);
|
||||
builtin_to_scode(_Env, crypto_blake2b, [_] = _Args) ->
|
||||
?TODO(fate_crypto_blake2b_instruction);
|
||||
builtin_to_scode(_Env, auth_tx_hash, none) ->
|
||||
?TODO(fate_auth_tx_hash_instruction);
|
||||
builtin_to_scode(_, B, Args) ->
|
||||
?TODO({builtin, B, Args}).
|
||||
|
||||
%% -- Operators --
|
||||
|
||||
binop_to_scode('+') -> aeb_fate_code:add(?a, ?a, ?a);
|
||||
binop_to_scode('-') -> aeb_fate_code:sub(?a, ?a, ?a);
|
||||
binop_to_scode('*') -> aeb_fate_code:mul(?a, ?a, ?a);
|
||||
binop_to_scode('/') -> aeb_fate_code:divide(?a, ?a, ?a);
|
||||
binop_to_scode(mod) -> aeb_fate_code:modulo(?a, ?a, ?a);
|
||||
binop_to_scode('^') -> aeb_fate_code:pow(?a, ?a, ?a);
|
||||
binop_to_scode('++') -> aeb_fate_code:append(?a, ?a, ?a);
|
||||
binop_to_scode('::') -> aeb_fate_code:cons(?a, ?a, ?a);
|
||||
binop_to_scode('<') -> aeb_fate_code:lt(?a, ?a, ?a);
|
||||
binop_to_scode('>') -> aeb_fate_code:gt(?a, ?a, ?a);
|
||||
binop_to_scode('=<') -> aeb_fate_code:elt(?a, ?a, ?a);
|
||||
binop_to_scode('>=') -> aeb_fate_code:egt(?a, ?a, ?a);
|
||||
binop_to_scode('==') -> aeb_fate_code:eq(?a, ?a, ?a);
|
||||
binop_to_scode('!=') -> aeb_fate_code:neq(?a, ?a, ?a).
|
||||
|
||||
unop_to_scode('!') -> aeb_fate_code:not_op(?a, ?a).
|
||||
op_to_scode('+') -> aeb_fate_code:add(?a, ?a, ?a);
|
||||
op_to_scode('-') -> aeb_fate_code:sub(?a, ?a, ?a);
|
||||
op_to_scode('*') -> aeb_fate_code:mul(?a, ?a, ?a);
|
||||
op_to_scode('/') -> aeb_fate_code:divide(?a, ?a, ?a);
|
||||
op_to_scode(mod) -> aeb_fate_code:modulo(?a, ?a, ?a);
|
||||
op_to_scode('^') -> aeb_fate_code:pow(?a, ?a, ?a);
|
||||
op_to_scode('++') -> aeb_fate_code:append(?a, ?a, ?a);
|
||||
op_to_scode('::') -> aeb_fate_code:cons(?a, ?a, ?a);
|
||||
op_to_scode('<') -> aeb_fate_code:lt(?a, ?a, ?a);
|
||||
op_to_scode('>') -> aeb_fate_code:gt(?a, ?a, ?a);
|
||||
op_to_scode('=<') -> aeb_fate_code:elt(?a, ?a, ?a);
|
||||
op_to_scode('>=') -> aeb_fate_code:egt(?a, ?a, ?a);
|
||||
op_to_scode('==') -> aeb_fate_code:eq(?a, ?a, ?a);
|
||||
op_to_scode('!=') -> aeb_fate_code:neq(?a, ?a, ?a);
|
||||
op_to_scode('!') -> aeb_fate_code:not_op(?a, ?a);
|
||||
op_to_scode(map_from_list) -> aeb_fate_code:map_from_list(?a, ?a);
|
||||
op_to_scode(map_to_list) -> ?TODO(fate_map_to_list_instruction);
|
||||
op_to_scode(map_delete) -> aeb_fate_code:map_delete(?a, ?a, ?a);
|
||||
op_to_scode(map_member) -> aeb_fate_code:map_member(?a, ?a, ?a);
|
||||
op_to_scode(map_size) -> ?TODO(fate_map_size_instruction);
|
||||
op_to_scode(string_length) -> ?TODO(fate_string_length_instruction);
|
||||
op_to_scode(string_concat) -> aeb_fate_code:str_join(?a, ?a, ?a);
|
||||
op_to_scode(bits_set) -> aeb_fate_code:bits_set(?a, ?a, ?a);
|
||||
op_to_scode(bits_clear) -> aeb_fate_code:bits_clear(?a, ?a, ?a);
|
||||
op_to_scode(bits_test) -> aeb_fate_code:bits_test(?a, ?a, ?a);
|
||||
op_to_scode(bits_sum) -> aeb_fate_code:bits_sum(?a, ?a);
|
||||
op_to_scode(bits_intersection) -> aeb_fate_code:bits_and(?a, ?a, ?a);
|
||||
op_to_scode(bits_union) -> aeb_fate_code:bits_or(?a, ?a, ?a);
|
||||
op_to_scode(bits_difference) -> aeb_fate_code:bits_diff(?a, ?a, ?a);
|
||||
op_to_scode(address_to_str) -> aeb_fate_code:addr_to_str(?a, ?a);
|
||||
op_to_scode(int_to_str) -> aeb_fate_code:int_to_str(?a, ?a).
|
||||
|
||||
%% PUSH and STORE ?a are the same, so we use STORE to make optimizations
|
||||
%% easier, and specialize to PUSH (which is cheaper) at the end.
|
||||
@ -614,7 +705,8 @@ attributes(I) ->
|
||||
{'BITS_AND', A, B, C} -> Pure(A, [B, C]);
|
||||
{'BITS_DIFF', A, B, C} -> Pure(A, [B, C]);
|
||||
{'ADDRESS', A} -> Pure(A, []);
|
||||
{'BALANCE', A} -> Pure(A, []);
|
||||
{'BALANCE', A} -> Impure(A, []);
|
||||
{'BALANCE_OTHER', A, B} -> Impure(A, [B]);
|
||||
{'ORIGIN', A} -> Pure(A, []);
|
||||
{'CALLER', A} -> Pure(A, []);
|
||||
{'GASPRICE', A} -> Pure(A, []);
|
||||
@ -633,6 +725,7 @@ attributes(I) ->
|
||||
{'LOG4', A, B, C, D, E, F} -> Impure(none, [A, B, C, D, E, F]);
|
||||
'DEACTIVATE' -> Impure(none, []);
|
||||
{'SPEND', A, B} -> Impure(none, [A, B]);
|
||||
|
||||
{'ORACLE_REGISTER', A, B, C, D, E, F} -> Impure(A, [B, C, D, E, F]);
|
||||
'ORACLE_QUERY' -> Impure(?a, []); %% TODO
|
||||
'ORACLE_RESPOND' -> Impure(?a, []); %% TODO
|
||||
@ -1219,14 +1312,10 @@ chase_labels([L | Ls], Map, Live) ->
|
||||
chase_labels(New ++ Ls, Map, Live#{ L => true }).
|
||||
|
||||
%% Replace PUSH, RETURN by RETURNR, drop returns after tail calls.
|
||||
tweak_returns(['RETURN', {'PUSH', A} | Code]) ->
|
||||
[{'RETURNR', A} | Code];
|
||||
%% tweak_returns(['RETURN', {'PUSH', A} | Code]) ->
|
||||
%% [{'RETURNR', A} | Code];
|
||||
tweak_returns(['RETURN' | Code = [{'CALL_T', _} | _]]) ->
|
||||
Code;
|
||||
tweak_returns(['RETURN' | Code = [{'CALL_TR', _, _} | _]]) ->
|
||||
Code;
|
||||
tweak_returns(['RETURN', {'PUSH', A} | Code]) -> [{'RETURNR', A} | Code];
|
||||
tweak_returns(['RETURN' | Code = [{'CALL_T', _} | _]]) -> Code;
|
||||
tweak_returns(['RETURN' | Code = [{'CALL_TR', _, _} | _]]) -> Code;
|
||||
tweak_returns(['RETURN' | Code = [{'ABORT', _} | _]]) -> Code;
|
||||
tweak_returns(Code) -> Code.
|
||||
|
||||
%% -- Split basic blocks at CALL instructions --
|
||||
|
Loading…
x
Reference in New Issue
Block a user