diff --git a/src/aeso_ast_to_fcode.erl b/src/aeso_ast_to_fcode.erl index 8b99401..1fac9ba 100644 --- a/src/aeso_ast_to_fcode.erl +++ b/src/aeso_ast_to_fcode.erl @@ -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? - con_env => #{["None"] => #con_tag{ tag = 0, arities = [0, 1] }, - ["Some"] => #con_tag{ tag = 1, arities = [0, 1] } + fun_env => #{}, + builtins => builtins(), + con_env => #{["None"] => #con_tag{ tag = 0, 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. + diff --git a/src/aeso_fcode_to_fate.erl b/src/aeso_fcode_to_fate.erl index 8ef2e13..1115f87 100644 --- a/src/aeso_fcode_to_fate.erl +++ b/src/aeso_fcode_to_fate.erl @@ -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 --