Contract factories and bytecode introspection #796

Merged
zxq9 merged 34 commits from factories into master 2021-05-18 19:21:57 +09:00
5 changed files with 40 additions and 24 deletions
Showing only changes of commit c8853b2103 - Show all commits

View File

@ -133,6 +133,7 @@
-define(PRINT_TYPES(Fmt, Args), -define(PRINT_TYPES(Fmt, Args),
when_option(pp_types, fun () -> io:format(Fmt, Args) end)). when_option(pp_types, fun () -> io:format(Fmt, Args) end)).
-define(CONSTRUCTOR_MOCK_NAME, "#__constructor__#").
%% -- Environment manipulation ----------------------------------------------- %% -- Environment manipulation -----------------------------------------------
@ -271,20 +272,25 @@ bind_contract({Contract, Ann, Id, Contents}, Env)
Fields = Fields =
[ {field_t, AnnF, Entrypoint, contract_call_type(Type)} [ {field_t, AnnF, Entrypoint, contract_call_type(Type)}
|| {fun_decl, AnnF, Entrypoint, Type} <- Contents ] ++ || {fun_decl, AnnF, Entrypoint, Type} <- Contents ] ++
[ begin [ {field_t, AnnF, Entrypoint,
AnnF1 = case {Contract, Name} of
{contract_child, "init"} -> [stateful,payable|AnnF]; %% for create/clone
_ -> AnnF
end,
{field_t, AnnF1, Entrypoint,
contract_call_type( contract_call_type(
{fun_t, AnnF1, [], [ArgT || {typed, _, _, ArgT} <- if is_list(Args) -> Args; true -> [Args] end], RetT}) {fun_t, AnnF, [], [ArgT || {typed, _, _, ArgT} <- Args], RetT})
} }
end || {letfun, AnnF, Entrypoint = {id, _, Name}, Args, _Type, {typed, _, _, RetT}} <- Contents,
|| {letfun, AnnF, Entrypoint = {id, _, Name}, Args, _Type, {typed, _, _, RetT}} <- Contents Name =/= "init"
] ++ ] ++
%% Predefined fields %% Predefined fields
[ {field_t, Sys, {id, Sys, "address"}, {id, Sys, "address"}} ], [ {field_t, Sys, {id, Sys, "address"}, {id, Sys, "address"}} ] ++
[ {field_t, Sys, {id, Sys, ?CONSTRUCTOR_MOCK_NAME},
contract_call_type(
case [ {fun_t, [payable|Sys], [], [ArgT || {typed, _, _, ArgT} <- Args], {id, Sys, "void"}}
|| {letfun, _, {id, _, "init"}, Args, _, _} <- Contents] of
[] -> {fun_t, [payable|Sys], [], [], {id, Sys, "void"}};
[T] -> T
end
)
}
],
FieldInfo = [ {Entrypoint, #field_info{ ann = FieldAnn, FieldInfo = [ {Entrypoint, #field_info{ ann = FieldAnn,
kind = contract, kind = contract,
field_t = Type, field_t = Type,
@ -1626,7 +1632,7 @@ check_contract_construction(Env, ContractT, Fun, NamedArgsT, ArgTypes, RetT) ->
unify(Env, RetT, ContractT, {return_contract, Fun, ContractT}), unify(Env, RetT, ContractT, {return_contract, Fun, ContractT}),
constrain([ #field_constraint{ constrain([ #field_constraint{
record_t = unfold_types_in_type(Env, ContractT), record_t = unfold_types_in_type(Env, ContractT),
field = {id, Ann, "init"}, field = {id, Ann, ?CONSTRUCTOR_MOCK_NAME},
field_t = InitT, field_t = InitT,
kind = project, kind = project,
context = {var_args, Ann, Fun} } context = {var_args, Ann, Fun} }
@ -2418,11 +2424,10 @@ unify1(_Env, {fun_t, _, _, var_args, _}, {fun_t, _, _, _, _}, When) ->
error({unify_varargs, When}); error({unify_varargs, When});
unify1(Env, {fun_t, _, Named1, Args1, Result1}, {fun_t, _, Named2, Args2, Result2}, When) unify1(Env, {fun_t, _, Named1, Args1, Result1}, {fun_t, _, Named2, Args2, Result2}, When)
when length(Args1) == length(Args2) -> when length(Args1) == length(Args2) ->
Named1_ = if is_list(Named1) -> lists:keysort(3, Named1); {Named1_, Named2_} =
true -> Named1 if is_list(Named1) andalso is_list(Named2) ->
end, {lists:keysort(3, Named1), lists:keysort(3, Named2)};
Named2_ = if is_list(Named2) -> lists:keysort(3, Named2); true -> {Named1, Named2}
true -> Named2
end, end,
unify(Env, Named1_, Named2_, When) andalso unify(Env, Named1_, Named2_, When) andalso
unify(Env, Args1, Args2, When) andalso unify(Env, Result1, Result2, When); unify(Env, Args1, Args2, When) andalso unify(Env, Result1, Result2, When);

View File

@ -707,6 +707,7 @@ expr_to_fcode(Env, _Type, {app, _Ann, {Op, _}, [A]}) when is_atom(Op) ->
%% Function calls %% Function calls
expr_to_fcode(Env, Type, {app, _, Fun = {typed, _, FunE, {fun_t, _, NamedArgsT, ArgsT, _}}, Args}) -> expr_to_fcode(Env, Type, {app, _, Fun = {typed, _, FunE, {fun_t, _, NamedArgsT, ArgsT, _}}, Args}) ->
io:format("Named args: ~p\n", [[N||{named_arg_t, _, {id, _, N}, _, _} <- NamedArgsT]]),
Args1 = get_named_args(NamedArgsT, Args), Args1 = get_named_args(NamedArgsT, Args),
FArgs = [expr_to_fcode(Env, Arg) || Arg <- Args1], FArgs = [expr_to_fcode(Env, Arg) || Arg <- Args1],
case expr_to_fcode(Env, Fun) of case expr_to_fcode(Env, Fun) of
@ -728,7 +729,7 @@ expr_to_fcode(Env, Type, {app, _, Fun = {typed, _, FunE, {fun_t, _, NamedArgsT,
end; end;
{builtin_u, B, _Ar} -> builtin_to_fcode(state_layout(Env), B, FArgs); {builtin_u, B, _Ar} -> builtin_to_fcode(state_layout(Env), B, FArgs);
{def_u, F, _Ar} -> {def, F, FArgs}; {def_u, F, _Ar} -> {def, F, FArgs};
{remote_u, ArgsT, RetT, Ct, RFun} -> {remote, ArgsT, RetT, Ct, RFun, FArgs}; {remote_u, RArgsT, RRetT, Ct, RFun} -> {remote, RArgsT, RRetT, Ct, RFun, FArgs};
FFun -> FFun ->
%% FFun is a closure, with first component the function name and %% FFun is a closure, with first component the function name and
%% second component the environment %% second component the environment

View File

@ -328,6 +328,7 @@ to_scode1(Env, {remote, ArgsT, RetT, Ct, Fun, [Gas, Value, Protected | Args]}) -
{ArgTypes, RetType0} = typesig_to_scode([{"_", T} || T <- ArgsT], RetT), {ArgTypes, RetType0} = typesig_to_scode([{"_", T} || T <- ArgsT], RetT),
ArgType = ?i(aeb_fate_data:make_typerep({tuple, ArgTypes})), ArgType = ?i(aeb_fate_data:make_typerep({tuple, ArgTypes})),
RetType = ?i(aeb_fate_data:make_typerep(RetType0)), RetType = ?i(aeb_fate_data:make_typerep(RetType0)),
io:format("GAS: ~p, VALUE: ~p, PROT: ~p\n", [Gas, Value, Protected]),
case Protected of case Protected of
{lit, {bool, false}} -> {lit, {bool, false}} ->
case Gas of case Gas of

View File

@ -26,13 +26,14 @@ run_test(Test) ->
simple_compile_test_() -> simple_compile_test_() ->
[ {"Testing the " ++ ContractName ++ " contract with the " ++ atom_to_list(Backend) ++ " backend", [ {"Testing the " ++ ContractName ++ " contract with the " ++ atom_to_list(Backend) ++ " backend",
fun() -> fun() ->
case compile(Backend, ContractName) of case compile(Backend, ContractName, [pp_assembler]) of
#{byte_code := ByteCode, #{byte_code := ByteCode,
contract_source := _, contract_source := _,
type_info := _} when Backend == aevm -> type_info := _} when Backend == aevm ->
?assertMatch(Code when is_binary(Code), ByteCode); ?assertMatch(Code when is_binary(Code), ByteCode);
#{fate_code := Code} when Backend == fate -> #{fate_code := Code} when Backend == fate ->
Code1 = aeb_fate_code:deserialize(aeb_fate_code:serialize(Code)), Code1 = aeb_fate_code:deserialize(aeb_fate_code:serialize(Code)),
error(xd),
?assertMatch({X, X}, {Code1, Code}); ?assertMatch({X, X}, {Code1, Code});
ErrBin -> ErrBin ->
io:format("\n~s", [ErrBin]), io:format("\n~s", [ErrBin]),

View File

@ -1,6 +1,14 @@
// If you need a quick compiler test — this file is for your playground contract T =
entrypoint f(x, y) = 3
main contract IntegerAdderFactory =
stateful payable entrypoint calculateSomething(x, t) =
// let t = Chain.create(value = 5555) : T
t.f(protected = true, gas = 999999999, value = 777777, 111, 222)
// t.f()
/*
contract IntegerAdder = contract IntegerAdder =
entrypoint init() = unit entrypoint init() = ()
entrypoint addIntegers(x, y) = x + y entrypoint addIntegers(x, y) = x + y
contract IntegerAdderHolder = contract IntegerAdderHolder =
@ -17,4 +25,4 @@ main contract EnterpriseContract =
entrypoint calculateSomething(x) = entrypoint calculateSomething(x) =
let adder = IntegerAdderFactory.new() let adder = IntegerAdderFactory.new()
adder.addIntegers(x, 2137) adder.addIntegers(x, 2137)
*/