Merge pull request #139 from aeternity/no-call-init
No calls to init-function (except when creating contract)
This commit is contained in:
commit
f8cd3b87f3
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
{erl_opts, [debug_info]}.
|
{erl_opts, [debug_info]}.
|
||||||
|
|
||||||
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {ref,"72b2a58"}}}
|
{deps, [ {aebytecode, {git, "https://github.com/aeternity/aebytecode.git", {ref,"5e16b85"}}}
|
||||||
, {getopt, "1.0.1"}
|
, {getopt, "1.0.1"}
|
||||||
, {eblake2, "1.0.0"}
|
, {eblake2, "1.0.0"}
|
||||||
, {jsx, {git, "https://github.com/talentdeficit/jsx.git",
|
, {jsx, {git, "https://github.com/talentdeficit/jsx.git",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{"1.1.0",
|
{"1.1.0",
|
||||||
[{<<"aebytecode">>,
|
[{<<"aebytecode">>,
|
||||||
{git,"https://github.com/aeternity/aebytecode.git",
|
{git,"https://github.com/aeternity/aebytecode.git",
|
||||||
{ref,"72b2a581d5a6d488a208331da88de1a488ac2da1"}},
|
{ref,"5e16b85ae2385bdc010f319e2f2717c09cac3621"}},
|
||||||
0},
|
0},
|
||||||
{<<"aeserialization">>,
|
{<<"aeserialization">>,
|
||||||
{git,"https://github.com/aeternity/aeserialization.git",
|
{git,"https://github.com/aeternity/aeserialization.git",
|
||||||
|
@ -106,6 +106,7 @@
|
|||||||
, in_pattern = false :: boolean()
|
, in_pattern = false :: boolean()
|
||||||
, stateful = false :: boolean()
|
, stateful = false :: boolean()
|
||||||
, current_function = none :: none | aeso_syntax:id()
|
, current_function = none :: none | aeso_syntax:id()
|
||||||
|
, what = top :: top | namespace | contract
|
||||||
}).
|
}).
|
||||||
|
|
||||||
-type env() :: #env{}.
|
-type env() :: #env{}.
|
||||||
@ -162,7 +163,7 @@ check_tvar(#env{ typevars = TVars}, T = {tvar, _, X}) ->
|
|||||||
|
|
||||||
-spec bind_fun(name(), type() | typesig(), env()) -> env().
|
-spec bind_fun(name(), type() | typesig(), env()) -> env().
|
||||||
bind_fun(X, Type, Env) ->
|
bind_fun(X, Type, Env) ->
|
||||||
case lookup_name(Env, [X]) of
|
case lookup_env(Env, term, [], [X]) of
|
||||||
false -> force_bind_fun(X, Type, Env);
|
false -> force_bind_fun(X, Type, Env);
|
||||||
{_QId, {Ann1, _}} ->
|
{_QId, {Ann1, _}} ->
|
||||||
type_error({duplicate_definition, X, [Ann1, aeso_syntax:get_ann(Type)]}),
|
type_error({duplicate_definition, X, [Ann1, aeso_syntax:get_ann(Type)]}),
|
||||||
@ -172,8 +173,13 @@ bind_fun(X, Type, Env) ->
|
|||||||
-spec force_bind_fun(name(), type() | typesig(), env()) -> env().
|
-spec force_bind_fun(name(), type() | typesig(), env()) -> env().
|
||||||
force_bind_fun(X, Type, Env) ->
|
force_bind_fun(X, Type, Env) ->
|
||||||
Ann = aeso_syntax:get_ann(Type),
|
Ann = aeso_syntax:get_ann(Type),
|
||||||
|
NoCode = get_option(no_code, false),
|
||||||
|
Entry = case X == "init" andalso Env#env.what == contract andalso not NoCode of
|
||||||
|
true -> {reserved_init, Ann, Type};
|
||||||
|
false -> {Ann, Type}
|
||||||
|
end,
|
||||||
on_current_scope(Env, fun(Scope = #scope{ funs = Funs }) ->
|
on_current_scope(Env, fun(Scope = #scope{ funs = Funs }) ->
|
||||||
Scope#scope{ funs = [{X, {Ann, Type}} | Funs] }
|
Scope#scope{ funs = [{X, Entry} | Funs] }
|
||||||
end).
|
end).
|
||||||
|
|
||||||
-spec bind_funs([{name(), type() | typesig()}], env()) -> env().
|
-spec bind_funs([{name(), type() | typesig()}], env()) -> env().
|
||||||
@ -253,34 +259,32 @@ possible_scopes(#env{ namespace = Current}, Name) ->
|
|||||||
Qual = lists:droplast(Name),
|
Qual = lists:droplast(Name),
|
||||||
[ lists:sublist(Current, I) ++ Qual || I <- lists:seq(0, length(Current)) ].
|
[ lists:sublist(Current, I) ++ Qual || I <- lists:seq(0, length(Current)) ].
|
||||||
|
|
||||||
-spec lookup_name(env(), qname()) -> false | {qname(), fun_info()}.
|
|
||||||
lookup_name(Env, Name) ->
|
|
||||||
lookup_env(Env, term, Name).
|
|
||||||
|
|
||||||
-spec lookup_type(env(), type_id()) -> false | {qname(), type_info()}.
|
-spec lookup_type(env(), type_id()) -> false | {qname(), type_info()}.
|
||||||
lookup_type(Env, Id) ->
|
lookup_type(Env, Id) ->
|
||||||
lookup_env(Env, type, qname(Id)).
|
lookup_env(Env, type, aeso_syntax:get_ann(Id), qname(Id)).
|
||||||
|
|
||||||
-spec lookup_env(env(), term, qname()) -> false | {qname(), fun_info()};
|
-spec lookup_env(env(), term, aeso_syntax:ann(), qname()) -> false | {qname(), fun_info()};
|
||||||
(env(), type, qname()) -> false | {qname(), type_info()}.
|
(env(), type, aeso_syntax:ann(), qname()) -> false | {qname(), type_info()}.
|
||||||
lookup_env(Env, Kind, Name) ->
|
lookup_env(Env, Kind, Ann, Name) ->
|
||||||
Var = case Name of
|
Var = case Name of
|
||||||
[X] when Kind == term -> proplists:get_value(X, Env#env.vars, false);
|
[X] when Kind == term -> proplists:get_value(X, Env#env.vars, false);
|
||||||
_ -> false
|
_ -> false
|
||||||
end,
|
end,
|
||||||
case Var of
|
case Var of
|
||||||
{Ann, Type} -> {Name, {Ann, Type}};
|
{Ann1, Type} -> {Name, {Ann1, Type}};
|
||||||
false ->
|
false ->
|
||||||
Names = [ Qual ++ [lists:last(Name)] || Qual <- possible_scopes(Env, Name) ],
|
Names = [ Qual ++ [lists:last(Name)] || Qual <- possible_scopes(Env, Name) ],
|
||||||
case [ Res || QName <- Names, Res <- [lookup_env1(Env, Kind, QName)], Res /= false] of
|
case [ Res || QName <- Names, Res <- [lookup_env1(Env, Kind, Ann, QName)], Res /= false] of
|
||||||
[] -> false;
|
[] -> false;
|
||||||
[Res] -> Res;
|
[Res] -> Res;
|
||||||
Many -> type_error({ambiguous_name, [{qid, Ann, Q} || {Q, {Ann, _}} <- Many]})
|
Many ->
|
||||||
|
type_error({ambiguous_name, [{qid, A, Q} || {Q, {A, _}} <- Many]}),
|
||||||
|
false
|
||||||
end
|
end
|
||||||
end.
|
end.
|
||||||
|
|
||||||
-spec lookup_env1(env(), type | term, qname()) -> false | {qname(), fun_info()}.
|
-spec lookup_env1(env(), type | term, aeso_syntax:ann(), qname()) -> false | {qname(), fun_info()}.
|
||||||
lookup_env1(#env{ namespace = Current, scopes = Scopes }, Kind, QName) ->
|
lookup_env1(#env{ namespace = Current, scopes = Scopes }, Kind, Ann, QName) ->
|
||||||
Qual = lists:droplast(QName),
|
Qual = lists:droplast(QName),
|
||||||
Name = lists:last(QName),
|
Name = lists:last(QName),
|
||||||
AllowPrivate = lists:prefix(Qual, Current),
|
AllowPrivate = lists:prefix(Qual, Current),
|
||||||
@ -295,9 +299,12 @@ lookup_env1(#env{ namespace = Current, scopes = Scopes }, Kind, QName) ->
|
|||||||
%% Look up the unqualified name
|
%% Look up the unqualified name
|
||||||
case proplists:get_value(Name, Defs, false) of
|
case proplists:get_value(Name, Defs, false) of
|
||||||
false -> false;
|
false -> false;
|
||||||
{Ann, _} = E ->
|
{reserved_init, Ann1, Type} ->
|
||||||
|
type_error({cannot_call_init_function, Ann}),
|
||||||
|
{QName, {Ann1, Type}}; %% Return the type to avoid an extra not-in-scope error
|
||||||
|
{Ann1, _} = E ->
|
||||||
%% Check that it's not private (or we can see private funs)
|
%% Check that it's not private (or we can see private funs)
|
||||||
case not is_private(Ann) orelse AllowPrivate of
|
case not is_private(Ann1) orelse AllowPrivate of
|
||||||
true -> {QName, E};
|
true -> {QName, E};
|
||||||
false -> false
|
false -> false
|
||||||
end
|
end
|
||||||
@ -532,7 +539,7 @@ map_t(As, K, V) -> {app_t, As, {id, As, "map"}, [K, V]}.
|
|||||||
infer(Contracts) ->
|
infer(Contracts) ->
|
||||||
infer(Contracts, []).
|
infer(Contracts, []).
|
||||||
|
|
||||||
-type option() :: return_env | dont_unfold.
|
-type option() :: return_env | dont_unfold | no_code | term().
|
||||||
|
|
||||||
-spec init_env(list(option())) -> env().
|
-spec init_env(list(option())) -> env().
|
||||||
init_env(_Options) -> global_env().
|
init_env(_Options) -> global_env().
|
||||||
@ -602,7 +609,8 @@ infer_constant({letval, Attrs,_Pattern, Type, E}) ->
|
|||||||
%% infer_contract takes a proplist mapping global names to types, and
|
%% infer_contract takes a proplist mapping global names to types, and
|
||||||
%% a list of definitions.
|
%% a list of definitions.
|
||||||
-spec infer_contract(env(), contract | namespace, [aeso_syntax:decl()]) -> {env(), [aeso_syntax:decl()]}.
|
-spec infer_contract(env(), contract | namespace, [aeso_syntax:decl()]) -> {env(), [aeso_syntax:decl()]}.
|
||||||
infer_contract(Env, What, Defs) ->
|
infer_contract(Env0, What, Defs) ->
|
||||||
|
Env = Env0#env{ what = What },
|
||||||
Kind = fun({type_def, _, _, _, _}) -> type;
|
Kind = fun({type_def, _, _, _, _}) -> type;
|
||||||
({letfun, _, _, _, _, _}) -> function;
|
({letfun, _, _, _, _, _}) -> function;
|
||||||
({fun_decl, _, _, _}) -> prototype;
|
({fun_decl, _, _, _}) -> prototype;
|
||||||
@ -830,8 +838,8 @@ is_string_type({bytes_t, _, N}) -> N > 32;
|
|||||||
is_string_type(_) -> false.
|
is_string_type(_) -> false.
|
||||||
|
|
||||||
-spec check_constructor_overlap(env(), aeso_syntax:con(), type()) -> ok | no_return().
|
-spec check_constructor_overlap(env(), aeso_syntax:con(), type()) -> ok | no_return().
|
||||||
check_constructor_overlap(Env, Con = {con, _, Name}, NewType) ->
|
check_constructor_overlap(Env, Con = {con, Ann, Name}, NewType) ->
|
||||||
case lookup_name(Env, Name) of
|
case lookup_env(Env, term, Ann, Name) of
|
||||||
false -> ok;
|
false -> ok;
|
||||||
{_, {Ann, Type}} ->
|
{_, {Ann, Type}} ->
|
||||||
OldType = case Type of {type_sig, _, _, _, T} -> T;
|
OldType = case Type of {type_sig, _, _, _, T} -> T;
|
||||||
@ -965,7 +973,7 @@ lookup_name(Env, As, Name) ->
|
|||||||
lookup_name(Env, As, Name, []).
|
lookup_name(Env, As, Name, []).
|
||||||
|
|
||||||
lookup_name(Env, As, Id, Options) ->
|
lookup_name(Env, As, Id, Options) ->
|
||||||
case lookup_name(Env, qname(Id)) of
|
case lookup_env(Env, term, As, qname(Id)) of
|
||||||
false ->
|
false ->
|
||||||
type_error({unbound_variable, Id}),
|
type_error({unbound_variable, Id}),
|
||||||
{Id, fresh_uvar(As)};
|
{Id, fresh_uvar(As)};
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
-type fun_name() :: {entrypoint, binary()}
|
-type fun_name() :: {entrypoint, binary()}
|
||||||
| {local_fun, [string()]}
|
| {local_fun, [string()]}
|
||||||
| init | event.
|
| event.
|
||||||
-type var_name() :: string().
|
-type var_name() :: string().
|
||||||
-type sophia_name() :: [string()].
|
-type sophia_name() :: [string()].
|
||||||
|
|
||||||
@ -910,10 +910,9 @@ add_init_function(Env, StateType, Funs0) ->
|
|||||||
false ->
|
false ->
|
||||||
Funs = add_default_init_function(Env, StateType, Funs0),
|
Funs = add_default_init_function(Env, StateType, Funs0),
|
||||||
InitName = {entrypoint, <<"init">>},
|
InitName = {entrypoint, <<"init">>},
|
||||||
InitFun = #{ args := InitArgs } = maps:get(InitName, Funs, none),
|
InitFun = #{ body := InitBody} = maps:get(InitName, Funs),
|
||||||
Vars = [ {var, X} || {X, _} <- InitArgs ],
|
Funs#{ InitName => InitFun#{ return => {tuple, []},
|
||||||
Funs#{ init => InitFun#{ return => {tuple, []},
|
body => {builtin, set_state, [InitBody]} } }
|
||||||
body => {builtin, set_state, [{def, InitName, Vars}]} } }
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
add_default_init_function(_Env, StateType, Funs) ->
|
add_default_init_function(_Env, StateType, Funs) ->
|
||||||
@ -1460,7 +1459,6 @@ pp_fun(Name, #{ args := Args, return := Return, body := Body }) ->
|
|||||||
pp_text(" : "), pp_ftype(Return), pp_text(" =")]),
|
pp_text(" : "), pp_ftype(Return), pp_text(" =")]),
|
||||||
prettypr:nest(2, pp_fexpr(Body))).
|
prettypr:nest(2, pp_fexpr(Body))).
|
||||||
|
|
||||||
pp_fun_name(init) -> pp_text('INIT');
|
|
||||||
pp_fun_name(event) -> pp_text(event);
|
pp_fun_name(event) -> pp_text(event);
|
||||||
pp_fun_name({entrypoint, E}) -> pp_text(binary_to_list(E));
|
pp_fun_name({entrypoint, E}) -> pp_text(binary_to_list(E));
|
||||||
pp_fun_name({local_fun, Q}) -> pp_text(string:join(Q, ".")).
|
pp_fun_name({local_fun, Q}) -> pp_text(string:join(Q, ".")).
|
||||||
|
@ -144,7 +144,7 @@ string_to_code(ContractString, Options) ->
|
|||||||
Ast = parse(ContractString, Options),
|
Ast = parse(ContractString, Options),
|
||||||
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 | Options]),
|
||||||
pp_typed_ast(TypedAst, Options),
|
pp_typed_ast(TypedAst, Options),
|
||||||
case proplists:get_value(backend, Options, aevm) of
|
case proplists:get_value(backend, Options, aevm) of
|
||||||
aevm ->
|
aevm ->
|
||||||
|
@ -143,7 +143,6 @@ compile(FCode, Options) ->
|
|||||||
make_function_id(X) ->
|
make_function_id(X) ->
|
||||||
aeb_fate_code:symbol_identifier(make_function_name(X)).
|
aeb_fate_code:symbol_identifier(make_function_name(X)).
|
||||||
|
|
||||||
make_function_name(init) -> <<"INIT">>;
|
|
||||||
make_function_name(event) -> <<"Chain.event">>;
|
make_function_name(event) -> <<"Chain.event">>;
|
||||||
make_function_name({entrypoint, Name}) -> Name;
|
make_function_name({entrypoint, Name}) -> Name;
|
||||||
make_function_name({local_fun, Xs}) -> list_to_binary("." ++ string:join(Xs, ".")).
|
make_function_name({local_fun, Xs}) -> list_to_binary("." ++ string:join(Xs, ".")).
|
||||||
|
@ -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_code]) 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_code]) 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_code]),
|
||||||
|
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
@ -174,7 +174,7 @@ encode_decode_calldata(FunName, Types, 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, []),
|
||||||
{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_code]),
|
||||||
?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),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user