Fixed performance issues. Changed include management

This commit is contained in:
radrow 2019-08-07 12:56:16 +02:00
parent ba8138d892
commit 4d13e01177
9 changed files with 113 additions and 49 deletions

View File

@ -140,7 +140,16 @@ from_string1(fate, ContractString, Options) ->
-spec string_to_code(string(), options()) -> map(). -spec string_to_code(string(), options()) -> map().
string_to_code(ContractString, Options) -> string_to_code(ContractString, Options) ->
Ast = parse(ContractString, Options), Ast = case lists:member(no_implicit_stdlib, Options) of
true -> parse(ContractString, Options);
false ->
IncludedSTD = sets:from_list(
[aeso_parser:hash_include(F, C)
|| {F, C} <- aeso_stdlib:stdlib_list()]),
InitAst = parse(ContractString, IncludedSTD, Options),
STD = parse_stdlib(),
STD ++ InitAst
end,
pp_sophia_code(Ast, Options), pp_sophia_code(Ast, Options),
pp_ast(Ast, Options), pp_ast(Ast, Options),
{TypeEnv, TypedAst} = aeso_ast_infer_types:infer(Ast, [return_env]), {TypeEnv, TypedAst} = aeso_ast_infer_types:infer(Ast, [return_env]),
@ -569,6 +578,14 @@ pp(Code, Options, Option, PPFun) ->
%% ------------------------------------------------------------------- %% -------------------------------------------------------------------
%% TODO: Tempoary parser hook below... %% TODO: Tempoary parser hook below...
parse_stdlib() ->
lists:foldr(
fun ({Lib, LibCode}, Acc) ->
parse(LibCode, [{src_file, Lib}]) ++ Acc
end,
[],
aeso_stdlib:stdlib_list()).
sophia_type_to_typerep(String) -> sophia_type_to_typerep(String) ->
{ok, Ast} = aeso_parser:type(String), {ok, Ast} = aeso_parser:type(String),
try aeso_ast_to_icode:ast_typerep(Ast) of try aeso_ast_to_icode:ast_typerep(Ast) of
@ -577,8 +594,10 @@ sophia_type_to_typerep(String) ->
end. end.
parse(Text, Options) -> parse(Text, Options) ->
parse(Text, sets:new(), Options).
parse(Text, Included, Options) ->
%% Try and return something sensible here! %% Try and return something sensible here!
case aeso_parser:string(Text, Options) of case aeso_parser:string(Text, Included, Options) of
%% Yay, it worked! %% Yay, it worked!
{ok, Contract} -> Contract; {ok, Contract} -> Contract;
%% Scan errors. %% Scan errors.

View File

@ -7,6 +7,7 @@
-export([string/1, -export([string/1,
string/2, string/2,
string/3, string/3,
hash_include/2,
type/1]). type/1]).
-include("aeso_parse_lib.hrl"). -include("aeso_parse_lib.hrl").
@ -27,18 +28,11 @@ string(String, Opts) ->
false -> string(String, sets:new(), Opts) false -> string(String, sets:new(), Opts)
end. end.
-spec string(string(), sets:set(string()), aeso_compiler:options()) -> parse_result(). -spec string(string(), sets:set(binary()), aeso_compiler:options()) -> parse_result().
string(String, Included, Opts) -> string(String, Included, Opts) ->
case parse_and_scan(file(), String, Opts) of case parse_and_scan(file(), String, Opts) of
{ok, AST} -> {ok, AST} ->
STD = case lists:member(no_implicit_stdlib, Opts) of expand_includes(AST, Included, Opts);
false -> [{ include, [{src_file, File}, {origin, system}]
, {string, [{src_file, File}, {origin, system}], File}}
|| {File, _} <- aeso_stdlib:stdlib_list()
];
true -> []
end,
expand_includes(STD ++ AST, Included, Opts);
Err = {error, _} -> Err = {error, _} ->
Err Err
end. end.
@ -558,32 +552,28 @@ expand_includes(AST, Included, Opts) ->
expand_includes([], _Included, Acc, _Opts) -> expand_includes([], _Included, Acc, _Opts) ->
{ok, lists:reverse(Acc)}; {ok, lists:reverse(Acc)};
expand_includes([{include, Ann, S = {string, _, File}} | AST], Included, Acc, Opts) -> expand_includes([{include, Ann, {string, SAnn, File}} | AST], Included, Acc, Opts) ->
case sets:is_element(File, Included) of case get_include_code(File, Ann, Opts) of
false -> {ok, Code} ->
Opts1 = lists:keystore(src_file, 1, Opts, {src_file, File}), Hashed = hash_include(File, Code),
Included1 = sets:add_element(File, Included), case sets:is_element(Hashed, Included) of
case {read_file(File, Opts), maps:find(File, aeso_stdlib:stdlib())} of false ->
{{ok, _}, {ok,_ }} -> Opts1 = lists:keystore(src_file, 1, Opts, {src_file, File}),
return_error(ann_pos(Ann), "Illegal redefinition of standard library " ++ File); Included1 = sets:add_element(Hashed, Included),
{_, {ok, Lib}} -> case string(Code, Included1, Opts1) of
case string(Lib, Included1, [no_implicit_stdlib, Opts1]) of
{ok, AST1} -> {ok, AST1} ->
expand_includes(AST1 ++ AST, Included1, Acc, Opts); Dependencies = [ {include, Ann, {string, SAnn, Dep}}
|| Dep <- aeso_stdlib:dependencies(File)
],
expand_includes(Dependencies ++ AST1 ++ AST, Included1, Acc, Opts);
Err = {error, _} -> Err = {error, _} ->
Err Err
end; end;
{{ok, Bin}, _} -> true ->
case string(binary_to_list(Bin), Included1, Opts1) of expand_includes(AST, Included, Acc, Opts)
{ok, AST1} ->
expand_includes(AST1 ++ AST, Included1, Acc, Opts);
Err = {error, _} ->
Err
end;
{_, _} ->
{error, {get_pos(S), include_error, File}}
end; end;
true -> expand_includes(AST, Included, Acc, Opts) Err = {error, _} ->
Err
end; end;
expand_includes([E | AST], Included, Acc, Opts) -> expand_includes([E | AST], Included, Acc, Opts) ->
expand_includes(AST, Included, [E | Acc], Opts). expand_includes(AST, Included, [E | Acc], Opts).
@ -601,3 +591,20 @@ read_file(File, Opts) ->
end end
end. end.
get_include_code(File, Ann, Opts) ->
case {read_file(File, Opts), maps:find(File, aeso_stdlib:stdlib())} of
{{ok, _}, {ok,_ }} ->
return_error(ann_pos(Ann), "Illegal redefinition of standard library " ++ File);
{_, {ok, Lib}} ->
{ok, Lib};
{{ok, Bin}, _} ->
{ok, binary_to_list(Bin)};
{_, _} ->
{error, {ann_pos(Ann), include_error, File}}
end.
-spec hash_include(string() | binary(), string()) -> binary().
hash_include(File, Code) when is_binary(File) ->
hash_include(binary_to_list(File), Code);
hash_include(File, Code) when is_list(File) ->
{filename:basename(File), crypto:hash(sha256, Code)}.

View File

@ -10,7 +10,7 @@
-module(aeso_stdlib). -module(aeso_stdlib).
-export([stdlib/0, stdlib_list/0]). -export([stdlib/0, stdlib_list/0, dependencies/1]).
stdlib() -> stdlib() ->
maps:from_list(stdlib_list()). maps:from_list(stdlib_list()).
@ -23,6 +23,13 @@ stdlib_list() ->
, {<<"Triple.aes">>, std_triple()} , {<<"Triple.aes">>, std_triple()}
]. ].
dependencies(Q) ->
case Q of
<<"Option.aes">> ->
[<<"List.aes">>];
_ -> []
end.
std_func() -> std_func() ->
" "
namespace Func = namespace Func =
@ -286,8 +293,6 @@ namespace List =
". ".
std_option() -> " std_option() -> "
include \"List.aes\"
namespace Option = namespace Option =
function is_none(o : option('a)) : bool = switch(o) function is_none(o : option('a)) : bool = switch(o)

View File

@ -80,11 +80,11 @@ encode_decode_sophia_string(SophiaType, String) ->
, " record r = {x : an_alias(int), y : variant}\n" , " record r = {x : an_alias(int), y : variant}\n"
, " datatype variant = Red | Blue(map(string, int))\n" , " datatype variant = Red | Blue(map(string, int))\n"
, " entrypoint foo : arg_type => arg_type\n" ], , " entrypoint foo : arg_type => arg_type\n" ],
case aeso_compiler:check_call(lists:flatten(Code), "foo", [String], []) of case aeso_compiler:check_call(lists:flatten(Code), "foo", [String], [no_implicit_stdlib]) of
{ok, _, {[Type], _}, [Arg]} -> {ok, _, {[Type], _}, [Arg]} ->
io:format("Type ~p~n", [Type]), io:format("Type ~p~n", [Type]),
Data = encode(Arg), Data = encode(Arg),
case aeso_compiler:to_sophia_value(Code, "foo", ok, Data) of case aeso_compiler:to_sophia_value(Code, "foo", ok, Data, [no_implicit_stdlib]) of
{ok, Sophia} -> {ok, Sophia} ->
lists:flatten(io_lib:format("~s", [prettypr:format(aeso_pretty:expr(Sophia))])); lists:flatten(io_lib:format("~s", [prettypr:format(aeso_pretty:expr(Sophia))]));
{error, Err} -> {error, Err} ->
@ -152,7 +152,7 @@ oracle_test() ->
" Oracle.get_question(o, q)\n", " Oracle.get_question(o, q)\n",
{ok, _, {[word, word], {list, string}}, [16#123, 16#456]} = {ok, _, {[word, word], {list, string}}, [16#123, 16#456]} =
aeso_compiler:check_call(Contract, "question", ["ok_111111111111111111111111111111ZrdqRz9", aeso_compiler:check_call(Contract, "question", ["ok_111111111111111111111111111111ZrdqRz9",
"oq_1111111111111111111111111111113AFEFpt5"], []), "oq_1111111111111111111111111111113AFEFpt5"], [no_implicit_stdlib]),
ok. ok.
@ -162,7 +162,7 @@ permissive_literals_fail_test() ->
" stateful entrypoint haxx(o : oracle(list(string), option(int))) =\n" " stateful entrypoint haxx(o : oracle(list(string), option(int))) =\n"
" Chain.spend(o, 1000000)\n", " Chain.spend(o, 1000000)\n",
{error, <<"Type errors\nCannot unify", _/binary>>} = {error, <<"Type errors\nCannot unify", _/binary>>} =
aeso_compiler:check_call(Contract, "haxx", ["#123"], []), aeso_compiler:check_call(Contract, "haxx", ["#123"], [no_implicit_stdlib]),
ok. ok.
encode_decode_calldata(FunName, Types, Args) -> encode_decode_calldata(FunName, Types, Args) ->
@ -173,8 +173,8 @@ encode_decode_calldata(FunName, Types, Args, RetType) ->
encode_decode_calldata_(Code, FunName, Args, RetType). encode_decode_calldata_(Code, FunName, Args, RetType).
encode_decode_calldata_(Code, FunName, Args, RetVMType) -> encode_decode_calldata_(Code, FunName, Args, RetVMType) ->
{ok, Calldata} = aeso_compiler:create_calldata(Code, FunName, Args), {ok, Calldata} = aeso_compiler:create_calldata(Code, FunName, Args, [no_implicit_stdlib]),
{ok, _, {ArgTypes, RetType}, _} = aeso_compiler:check_call(Code, FunName, Args, [{backend, aevm}]), {ok, _, {ArgTypes, RetType}, _} = aeso_compiler:check_call(Code, FunName, Args, [{backend, aevm}, no_implicit_stdlib]),
?assertEqual(RetType, RetVMType), ?assertEqual(RetType, RetVMType),
CalldataType = {tuple, [word, {tuple, ArgTypes}]}, CalldataType = {tuple, [word, {tuple, ArgTypes}]},
{ok, {_Hash, ArgTuple}} = aeb_heap:from_binary(CalldataType, Calldata), {ok, {_Hash, ArgTuple}} = aeb_heap:from_binary(CalldataType, Calldata),
@ -182,7 +182,7 @@ encode_decode_calldata_(Code, FunName, Args, RetVMType) ->
"init" -> "init" ->
ok; ok;
_ -> _ ->
{ok, _ArgTypes, ValueASTs} = aeso_compiler:decode_calldata(Code, FunName, Calldata), {ok, _ArgTypes, ValueASTs} = aeso_compiler:decode_calldata(Code, FunName, Calldata, [no_implicit_stdlib]),
Values = [ prettypr:format(aeso_pretty:expr(V)) || V <- ValueASTs ], Values = [ prettypr:format(aeso_pretty:expr(V)) || V <- ValueASTs ],
?assertMatch({X, X}, {Args, Values}) ?assertMatch({X, X}, {Args, Values})
end, end,

View File

@ -87,7 +87,8 @@ aci_test_() ->
fun() -> aci_test_contract(ContractName) end} fun() -> aci_test_contract(ContractName) end}
|| ContractName <- all_contracts()]. || ContractName <- all_contracts()].
all_contracts() -> aeso_compiler_tests:compilable_contracts(). all_contracts() -> [C || C <- aeso_compiler_tests:compilable_contracts()
, not aeso_compiler_tests:wants_stdlib(C)].
aci_test_contract(Name) -> aci_test_contract(Name) ->
String = aeso_test_utils:read_contract(Name), String = aeso_test_utils:read_contract(Name),
@ -98,7 +99,7 @@ aci_test_contract(Name) ->
{ok, ContractStub} = aeso_aci:render_aci_json(JSON), {ok, ContractStub} = aeso_aci:render_aci_json(JSON),
io:format("STUB:\n~s\n", [ContractStub]), io:format("STUB:\n~s\n", [ContractStub]),
check_stub(ContractStub, [{src_file, Name}, no_implicit_stdlib]), check_stub(ContractStub, [{src_file, Name}]),
ok. ok.

View File

@ -21,12 +21,14 @@ calldata_test_() ->
ContractString = aeso_test_utils:read_contract(ContractName), ContractString = aeso_test_utils:read_contract(ContractName),
AevmExprs = AevmExprs =
case not lists:member(ContractName, not_yet_compilable(aevm)) of case not lists:member(ContractName, not_yet_compilable(aevm)) of
true -> ast_exprs(ContractString, Fun, Args, [{backend, aevm}]); true -> ast_exprs(ContractString, Fun, Args, [{backend, aevm}]
++ [no_implicit_stdlib || not aeso_compiler_tests:wants_stdlib(ContractName)]);
false -> undefined false -> undefined
end, end,
FateExprs = FateExprs =
case not lists:member(ContractName, not_yet_compilable(fate)) of case not lists:member(ContractName, not_yet_compilable(fate)) of
true -> ast_exprs(ContractString, Fun, Args, [{backend, fate}]); true -> ast_exprs(ContractString, Fun, Args, [{backend, fate}]
++ [no_implicit_stdlib || not aeso_compiler_tests:wants_stdlib(ContractName)]);
false -> undefined false -> undefined
end, end,
case FateExprs == undefined orelse AevmExprs == undefined of case FateExprs == undefined orelse AevmExprs == undefined of
@ -45,12 +47,14 @@ calldata_aci_test_() ->
io:format("ACI:\n~s\n", [ContractACIBin]), io:format("ACI:\n~s\n", [ContractACIBin]),
AevmExprs = AevmExprs =
case not lists:member(ContractName, not_yet_compilable(aevm)) of case not lists:member(ContractName, not_yet_compilable(aevm)) of
true -> ast_exprs(ContractACI, Fun, Args, [{backend, aevm}]); true -> ast_exprs(ContractACI, Fun, Args, [{backend, aevm}]
++ [no_implicit_stdlib || not aeso_compiler_tests:wants_stdlib(ContractName)]);
false -> undefined false -> undefined
end, end,
FateExprs = FateExprs =
case not lists:member(ContractName, not_yet_compilable(fate)) of case not lists:member(ContractName, not_yet_compilable(fate)) of
true -> ast_exprs(ContractACI, Fun, Args, [{backend, fate}]); true -> ast_exprs(ContractACI, Fun, Args, [{backend, fate}]
++ [no_implicit_stdlib || not aeso_compiler_tests:wants_stdlib(ContractName)]);
false -> undefined false -> undefined
end, end,
case FateExprs == undefined orelse AevmExprs == undefined of case FateExprs == undefined orelse AevmExprs == undefined of

View File

@ -73,7 +73,9 @@ check_errors(Expect, ErrorString) ->
end. end.
compile(Backend, Name) -> compile(Backend, Name) ->
compile(Backend, Name, [{include, {file_system, [aeso_test_utils:contract_path()]}}]). compile(Backend, Name,
[{include, {file_system, [aeso_test_utils:contract_path()]}}]
++ [no_implicit_stdlib || not wants_stdlib(Name)]).
compile(Backend, Name, Options) -> compile(Backend, Name, Options) ->
String = aeso_test_utils:read_contract(Name), String = aeso_test_utils:read_contract(Name),
@ -121,6 +123,8 @@ compilable_contracts() ->
"tuple_match", "tuple_match",
"cyclic_include", "cyclic_include",
"stdlib_include", "stdlib_include",
"double_include",
"manual_stdlib_include",
"list_comp" "list_comp"
]. ].
@ -367,3 +371,13 @@ failing_contracts() ->
[<<"Cannot unify int\n and string\nwhen checking the type of the pattern at line 2, column 53\n x : int\nagainst the expected type\n string">> [<<"Cannot unify int\n and string\nwhen checking the type of the pattern at line 2, column 53\n x : int\nagainst the expected type\n string">>
]} ]}
]. ].
wants_stdlib(Name) ->
lists:member
(Name,
[ "stdlib_include",
"list_comp",
"list_comp_not_a_list",
"list_comp_if_not_bool",
"list_comp_bad_shadow"
]).

View File

@ -0,0 +1,7 @@
include "included.aes"
include "../contracts/included.aes"
contract Include =
entrypoint foo() =
Included.foo()

View File

@ -0,0 +1,7 @@
// This contract should be compiled with no_implicit_stdlib option.
// It should include Lists.aes implicitly however, because Option.aes depends on it.
include "Option.aes"
contract Test =
entrypoint i_should_build() =
List.is_empty(Option.to_list(None))