Merge pull request #115 from aeternity/PT-166731397-add_compiler_backend
PT-166731397 Add compiler backend
This commit is contained in:
commit
6f7f5fa13c
@ -261,6 +261,11 @@ decls_to_fcode(Env, Decls) ->
|
|||||||
|
|
||||||
-spec decl_to_fcode(env(), aeso_syntax:decl()) -> env().
|
-spec decl_to_fcode(env(), aeso_syntax:decl()) -> env().
|
||||||
decl_to_fcode(Env, {type_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, {fun_decl, _, _, _}) -> Env;
|
||||||
decl_to_fcode(Env, {type_def, _Ann, Name, Args, Def}) ->
|
decl_to_fcode(Env, {type_def, _Ann, Name, Args, Def}) ->
|
||||||
typedef_to_fcode(Env, 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) ->
|
add_fun_env(Env = #{ fun_env := FunEnv }, Decls) ->
|
||||||
Entry = fun({letfun, Ann, {id, _, Name}, Args, _, _}) ->
|
Entry = fun({letfun, Ann, {id, _, Name}, Args, _, _}) ->
|
||||||
[{qname(Env, Name), {make_fun_name(Env, Ann, Name), length(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,
|
(_) -> [] end,
|
||||||
FunEnv1 = maps:from_list(lists:flatmap(Entry, Decls)),
|
FunEnv1 = maps:from_list(lists:flatmap(Entry, Decls)),
|
||||||
Env#{ fun_env := maps:merge(FunEnv, FunEnv1) }.
|
Env#{ fun_env := maps:merge(FunEnv, FunEnv1) }.
|
||||||
|
@ -21,18 +21,19 @@ convert_typed(TypedTree, Options) ->
|
|||||||
{contract, _, {con, _, Con}, _} -> Con;
|
{contract, _, {con, _, Con}, _} -> Con;
|
||||||
_ -> gen_error(last_declaration_must_be_contract)
|
_ -> gen_error(last_declaration_must_be_contract)
|
||||||
end,
|
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).
|
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)),
|
NewIcode = contract_to_icode(Code, aeso_icode:set_namespace(Con, Icode)),
|
||||||
code(Rest, NewIcode);
|
code(Rest, NewIcode, Options);
|
||||||
code([{namespace, _Ann, Name, Code}|Rest], Icode) ->
|
code([{namespace, _Ann, Name, Code}|Rest], Icode, Options) ->
|
||||||
%% TODO: nested namespaces
|
%% TODO: nested namespaces
|
||||||
NewIcode = contract_to_icode(Code, aeso_icode:set_namespace(Name, Icode)),
|
NewIcode = contract_to_icode(Code, aeso_icode:set_namespace(Name, Icode)),
|
||||||
code(Rest, NewIcode);
|
code(Rest, NewIcode, Options);
|
||||||
code([], Icode) ->
|
code([], Icode, Options) ->
|
||||||
add_default_init_function(add_builtins(Icode)).
|
add_default_init_function(add_builtins(Icode), Options).
|
||||||
|
|
||||||
%% Generate error on correct format.
|
%% Generate error on correct format.
|
||||||
|
|
||||||
@ -40,10 +41,12 @@ gen_error(Error) ->
|
|||||||
error({code_errors, [Error]}).
|
error({code_errors, [Error]}).
|
||||||
|
|
||||||
%% Create default init function (only if state is unit).
|
%% 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),
|
{_, _, QInit} = aeso_icode:qualify({id, [], "init"}, Icode),
|
||||||
case lists:keymember(QInit, 1, Funs) of
|
case lists:keymember(QInit, 1, Funs) of
|
||||||
true -> Icode;
|
true -> Icode;
|
||||||
|
false when NoCode -> Icode;
|
||||||
false when State /= {tuple, []} ->
|
false when State /= {tuple, []} ->
|
||||||
gen_error(missing_init_function);
|
gen_error(missing_init_function);
|
||||||
false ->
|
false ->
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
| pp_icode
|
| pp_icode
|
||||||
| pp_assembler
|
| pp_assembler
|
||||||
| pp_bytecode
|
| pp_bytecode
|
||||||
|
| no_code
|
||||||
| {backend, aevm | fate}
|
| {backend, aevm | fate}
|
||||||
| {include, {file_system, [string()]} |
|
| {include, {file_system, [string()]} |
|
||||||
{explicit_files, #{string() => binary()}}}
|
{explicit_files, #{string() => binary()}}}
|
||||||
@ -134,7 +135,7 @@ from_string1(fate, ContractString, Options) ->
|
|||||||
fate_code => FateCode
|
fate_code => FateCode
|
||||||
}}.
|
}}.
|
||||||
|
|
||||||
-spec string_to_code(string(), [option()]) -> map().
|
-spec string_to_code(string(), options()) -> map().
|
||||||
string_to_code(ContractString, Options) ->
|
string_to_code(ContractString, Options) ->
|
||||||
Ast = parse(ContractString, Options),
|
Ast = parse(ContractString, Options),
|
||||||
pp_sophia_code(Ast, Options),
|
pp_sophia_code(Ast, Options),
|
||||||
@ -361,7 +362,8 @@ create_calldata(Code, Fun, Args) ->
|
|||||||
-spec create_calldata(string(), string(), [string()], [{atom(), any()}]) ->
|
-spec create_calldata(string(), string(), [string()], [{atom(), any()}]) ->
|
||||||
{ok, binary()}
|
{ok, binary()}
|
||||||
| {error, term()}.
|
| {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
|
case proplists:get_value(backend, Options, aevm) of
|
||||||
aevm ->
|
aevm ->
|
||||||
case check_call(Code, Fun, Args, Options) of
|
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) ->
|
||||||
decode_calldata(ContractString, FunName, Calldata, [{backend, aevm}]).
|
decode_calldata(ContractString, FunName, Calldata, [{backend, aevm}]).
|
||||||
|
|
||||||
decode_calldata(ContractString, FunName, Calldata, Options) ->
|
decode_calldata(ContractString, FunName, Calldata, Options0) ->
|
||||||
|
Options = [no_code | Options0],
|
||||||
try
|
try
|
||||||
Code = string_to_code(ContractString, Options),
|
Code = string_to_code(ContractString, Options),
|
||||||
#{ typed_ast := TypedAst, type_env := TypeEnv} = Code,
|
#{ typed_ast := TypedAst, type_env := TypeEnv} = Code,
|
||||||
|
@ -36,10 +36,34 @@ calldata_test_() ->
|
|||||||
end
|
end
|
||||||
end} || {ContractName, Fun, Args} <- compilable_contracts()].
|
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) ->
|
ast_exprs(ContractString, Fun, Args, Opts) ->
|
||||||
{ok, Data} = aeso_compiler:create_calldata(ContractString, Fun, Args, Opts),
|
{ok, Data} = (catch aeso_compiler:create_calldata(ContractString, Fun, Args, Opts)),
|
||||||
{ok, _Types, Exprs} = aeso_compiler:decode_calldata(ContractString, Fun, Data, Opts),
|
{ok, _Types, Exprs} = (catch aeso_compiler:decode_calldata(ContractString, Fun, Data, Opts)),
|
||||||
?assert(is_list(Exprs)),
|
?assert(is_list(Exprs)),
|
||||||
Exprs.
|
Exprs.
|
||||||
|
|
||||||
@ -93,10 +117,12 @@ compilable_contracts() ->
|
|||||||
{"complex_types", "init", ["ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ"]},
|
{"complex_types", "init", ["ct_Ez6MyeTMm17YnTnDdHTSrzMEBKmy7Uz2sXu347bTDPgVH2ifJ"]},
|
||||||
{"__call" "init", []},
|
{"__call" "init", []},
|
||||||
{"bitcoin_auth", "authorize", ["1", "#0102030405060708090a0b0c0d0e0f101718192021222324252627282930313233343536373839401a1b1c1d1e1f202122232425262728293031323334353637"]},
|
{"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) ->
|
not_yet_compilable(fate) ->
|
||||||
["address_chain"];
|
[];
|
||||||
not_yet_compilable(aevm) ->
|
not_yet_compilable(aevm) ->
|
||||||
["__call"].
|
[].
|
||||||
|
2
test/contracts/stub.aes
Normal file
2
test/contracts/stub.aes
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
contract Stub =
|
||||||
|
entrypoint foo : (int) => int
|
Loading…
x
Reference in New Issue
Block a user