Merge pull request #115 from aeternity/PT-166731397-add_compiler_backend

PT-166731397 Add compiler backend
This commit is contained in:
Hans Svensson 2019-08-05 15:00:32 +02:00 committed by GitHub
commit 6f7f5fa13c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 58 additions and 17 deletions

View File

@ -261,6 +261,11 @@ decls_to_fcode(Env, Decls) ->
-spec decl_to_fcode(env(), aeso_syntax:decl()) -> env().
decl_to_fcode(Env, {type_decl, _, _, _}) -> Env;
decl_to_fcode(Env = #{context := {main_contract, _}}, {fun_decl, Ann, {id, _, Name}, _}) ->
case proplists:get_value(no_code, maps:get(options, Env, []), false) of
false -> fcode_error({missing_definition, Name, lists:keydelete(entrypoint, 1, Ann)});
true -> Env
end;
decl_to_fcode(Env, {fun_decl, _, _, _}) -> Env;
decl_to_fcode(Env, {type_def, _Ann, Name, Args, Def}) ->
typedef_to_fcode(Env, Name, Args, Def);
@ -1001,6 +1006,8 @@ add_fun_env(Env = #{ context := {abstract_contract, _} }, _) -> Env; %% no func
add_fun_env(Env = #{ fun_env := FunEnv }, Decls) ->
Entry = fun({letfun, Ann, {id, _, Name}, Args, _, _}) ->
[{qname(Env, Name), {make_fun_name(Env, Ann, Name), length(Args)}}];
({fun_decl, Ann, {id, _, Name}, {fun_t, _, _, ArgTypes, _}}) ->
[{qname(Env, Name), {make_fun_name(Env, Ann, Name), length(ArgTypes)}}];
(_) -> [] end,
FunEnv1 = maps:from_list(lists:flatmap(Entry, Decls)),
Env#{ fun_env := maps:merge(FunEnv, FunEnv1) }.

View File

@ -21,18 +21,19 @@ convert_typed(TypedTree, Options) ->
{contract, _, {con, _, Con}, _} -> Con;
_ -> gen_error(last_declaration_must_be_contract)
end,
Icode = code(TypedTree, aeso_icode:set_name(Name, aeso_icode:new(Options))),
NewIcode = aeso_icode:set_name(Name, aeso_icode:new(Options)),
Icode = code(TypedTree, NewIcode, Options),
deadcode_elimination(Icode).
code([{contract, _Attribs, Con, Code}|Rest], Icode) ->
code([{contract, _Attribs, Con, Code}|Rest], Icode, Options) ->
NewIcode = contract_to_icode(Code, aeso_icode:set_namespace(Con, Icode)),
code(Rest, NewIcode);
code([{namespace, _Ann, Name, Code}|Rest], Icode) ->
code(Rest, NewIcode, Options);
code([{namespace, _Ann, Name, Code}|Rest], Icode, Options) ->
%% TODO: nested namespaces
NewIcode = contract_to_icode(Code, aeso_icode:set_namespace(Name, Icode)),
code(Rest, NewIcode);
code([], Icode) ->
add_default_init_function(add_builtins(Icode)).
code(Rest, NewIcode, Options);
code([], Icode, Options) ->
add_default_init_function(add_builtins(Icode), Options).
%% Generate error on correct format.
@ -40,10 +41,12 @@ gen_error(Error) ->
error({code_errors, [Error]}).
%% Create default init function (only if state is unit).
add_default_init_function(Icode = #{functions := Funs, state_type := State}) ->
add_default_init_function(Icode = #{functions := Funs, state_type := State}, Options) ->
NoCode = proplists:get_value(no_code, Options, false),
{_, _, QInit} = aeso_icode:qualify({id, [], "init"}, Icode),
case lists:keymember(QInit, 1, Funs) of
true -> Icode;
false when NoCode -> Icode;
false when State /= {tuple, []} ->
gen_error(missing_init_function);
false ->

View File

@ -35,6 +35,7 @@
| pp_icode
| pp_assembler
| pp_bytecode
| no_code
| {backend, aevm | fate}
| {include, {file_system, [string()]} |
{explicit_files, #{string() => binary()}}}
@ -134,7 +135,7 @@ from_string1(fate, ContractString, Options) ->
fate_code => FateCode
}}.
-spec string_to_code(string(), [option()]) -> map().
-spec string_to_code(string(), options()) -> map().
string_to_code(ContractString, Options) ->
Ast = parse(ContractString, Options),
pp_sophia_code(Ast, Options),
@ -361,7 +362,8 @@ create_calldata(Code, Fun, Args) ->
-spec create_calldata(string(), string(), [string()], [{atom(), any()}]) ->
{ok, binary()}
| {error, term()}.
create_calldata(Code, Fun, Args, Options) ->
create_calldata(Code, Fun, Args, Options0) ->
Options = [no_code | Options0],
case proplists:get_value(backend, Options, aevm) of
aevm ->
case check_call(Code, Fun, Args, Options) of
@ -383,7 +385,8 @@ create_calldata(Code, Fun, Args, Options) ->
decode_calldata(ContractString, FunName, Calldata) ->
decode_calldata(ContractString, FunName, Calldata, [{backend, aevm}]).
decode_calldata(ContractString, FunName, Calldata, Options) ->
decode_calldata(ContractString, FunName, Calldata, Options0) ->
Options = [no_code | Options0],
try
Code = string_to_code(ContractString, Options),
#{ typed_ast := TypedAst, type_env := TypeEnv} = Code,

View File

@ -36,10 +36,34 @@ calldata_test_() ->
end
end} || {ContractName, Fun, Args} <- compilable_contracts()].
calldata_aci_test_() ->
[ {"Testing " ++ ContractName ++ " contract calling " ++ Fun,
fun() ->
ContractString = aeso_test_utils:read_contract(ContractName),
{ok, ContractACIBin} = aeso_aci:contract_interface(string, ContractString),
ContractACI = binary_to_list(ContractACIBin),
io:format("ACI:\n~s\n", [ContractACIBin]),
AevmExprs =
case not lists:member(ContractName, not_yet_compilable(aevm)) of
true -> ast_exprs(ContractACI, Fun, Args, [{backend, aevm}]);
false -> undefined
end,
FateExprs =
case not lists:member(ContractName, not_yet_compilable(fate)) of
true -> ast_exprs(ContractACI, Fun, Args, [{backend, fate}]);
false -> undefined
end,
case FateExprs == undefined orelse AevmExprs == undefined of
true -> ok;
false ->
?assertEqual(FateExprs, AevmExprs)
end
end} || {ContractName, Fun, Args} <- compilable_contracts()].
ast_exprs(ContractString, Fun, Args, Opts) ->
{ok, Data} = aeso_compiler:create_calldata(ContractString, Fun, Args, Opts),
{ok, _Types, Exprs} = aeso_compiler:decode_calldata(ContractString, Fun, Data, Opts),
{ok, Data} = (catch aeso_compiler:create_calldata(ContractString, Fun, Args, Opts)),
{ok, _Types, Exprs} = (catch aeso_compiler:decode_calldata(ContractString, Fun, Data, Opts)),
?assert(is_list(Exprs)),
Exprs.
@ -93,10 +117,12 @@ compilable_contracts() ->
{"complex_types", "init", ["ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ"]},
{"__call" "init", []},
{"bitcoin_auth", "authorize", ["1", "#0102030405060708090a0b0c0d0e0f101718192021222324252627282930313233343536373839401a1b1c1d1e1f202122232425262728293031323334353637"]},
{"bitcoin_auth", "to_sign", ["#0102030405060708090a0b0c0d0e0f1017181920212223242526272829303132", "2"]}
{"bitcoin_auth", "to_sign", ["#0102030405060708090a0b0c0d0e0f1017181920212223242526272829303132", "2"]},
{"stub", "foo", ["42"]},
{"stub", "foo", ["-42"]}
].
not_yet_compilable(fate) ->
["address_chain"];
[];
not_yet_compilable(aevm) ->
["__call"].
[].

2
test/contracts/stub.aes Normal file
View File

@ -0,0 +1,2 @@
contract Stub =
entrypoint foo : (int) => int