To sophia value revisited #521

Merged
zxq9 merged 6 commits from to-sophia-value-revisited into master 2019-02-27 19:36:04 +09:00
2 changed files with 31 additions and 32 deletions
Showing only changes of commit 5a4a84805f - Show all commits

View File

@ -11,8 +11,8 @@
-export([ file/1
, file/2
, from_string/2
, check_call/2
, create_calldata/3
, check_call/4
, create_calldata/4
, version/0
, sophia_type_to_typerep/1
, to_sophia_value/4
@ -110,10 +110,11 @@ join_errors(Prefix, Errors, Pfun) ->
%% function (foo, say) and a function __call() = foo(args) calling this
%% function. Returns the name of the called functions, typereps and Erlang
%% terms for the arguments.
-spec check_call(string(), options()) -> {ok, string(), {[Type], Type | any}, [term()]} | {error, term()}
-spec check_call(string(), string(), [string()], options()) -> {ok, string(), {[Type], Type | any}, [term()]} | {error, term()}
when Type :: term().
check_call(ContractString, Options) ->
check_call(ContractString0, FunName, Args, Options) ->
try
ContractString = insert_call_function(ContractString0, FunName, Args, Options),
Ast = parse(ContractString, Options),
ok = pp_sophia_code(Ast, Options),
ok = pp_ast(Ast, Options),
@ -145,6 +146,24 @@ check_call(ContractString, Options) ->
fun (E) -> io_lib:format("~p", [E]) end)}
end.
%% Add the __call function to a contract.
-spec insert_call_function(string(), string(), [string()], options()) -> string().
insert_call_function(Code, FunName, Args, Options) ->
Ast = parse(Code, Options),
Ind = last_contract_indent(Ast),
lists:flatten(
[ Code,
"\n\n",
lists:duplicate(Ind, " "),
"function __call() = ", FunName, "(", string:join(Args, ","), ")\n"
]).
last_contract_indent(Decls) ->
case lists:last(Decls) of
{_, _, _, [Decl | _]} -> aeso_syntax:get_ann(col, Decl, 1) - 1;
_ -> 0
end.
-spec to_sophia_value(string(), string(), ok | error | revert, aeso_sophia:data()) ->
{ok, aeso_syntax:expr()} | {error, term()}.
to_sophia_value(ContractString, Fun, ResType, Data) ->
@ -252,34 +271,16 @@ translate_vm_value(VmTypes, {constr_t, _, Con, Types}, Args)
translate_vm_value(_VmType, _Type, _Data) ->
throw(cannot_translate_to_sophia).
-spec create_calldata(map(), string(), string()) ->
-spec create_calldata(map(), string(), string(), [string()]) ->
{ok, binary(), aeso_sophia:type(), aeso_sophia:type()}
| {error, argument_syntax_error}.
create_calldata(Contract, "", CallCode) when is_map(Contract) ->
case check_call(CallCode, []) of
create_calldata(Contract, Code, Fun, Args) when is_map(Contract) ->
case check_call(Code, Fun, Args, []) of
{ok, FunName, {ArgTypes, RetType}, Args} ->
aeso_abi:create_calldata(Contract, FunName, Args, ArgTypes, RetType);
{error, _} = Err -> Err
end;
create_calldata(Contract, Function, Argument) when is_map(Contract) ->
%% Slightly hacky shortcut to let you get away without writing the full
%% call contract code.
%% Function should be "foo : type", and
%% Argument should be "Arg1, Arg2, .., ArgN" (no parens)
case string:lexemes(Function, ": ") of
%% If function is a single word fallback to old calldata generation
[FunName] -> aeso_abi:old_create_calldata(Contract, FunName, Argument);
[FunName | _] ->
Args = lists:map(fun($\n) -> 32; (X) -> X end, Argument), %% newline to space
CallContract = lists:flatten(
[ "contract MakeCall =\n"
, " function ", Function, "\n"
, " function __call() = ", FunName, "(", Args, ")"
]),
create_calldata(Contract, "", CallContract)
end.
get_arg_icode(Funs) ->
case [ Args || {[_, ?CALL_NAME], _, _, {funcall, _, Args}, _} <- Funs ] of
[Args] -> Args;

View File

@ -70,15 +70,13 @@ encode_decode_sophia_test() ->
encode_decode_sophia_string(SophiaType, String) ->
io:format("String ~p~n", [String]),
TypeDefs = [" type an_alias('a) = (string, 'a)\n",
" record r = {x : an_alias(int), y : variant}\n"
" datatype variant = Red | Blue(map(string, int))\n"],
Code = [ "contract MakeCall =\n"
, " type arg_type = ", SophiaType, "\n"
, TypeDefs
, " function foo : arg_type => arg_type\n"
, " function __call() = foo(", String, ")\n" ],
case aeso_compiler:check_call(lists:flatten(Code), []) of
, " type an_alias('a) = (string, 'a)\n"
, " record r = {x : an_alias(int), y : variant}\n"
, " datatype variant = Red | Blue(map(string, int))\n"
, " function foo : arg_type => arg_type\n" ],
case aeso_compiler:check_call(lists:flatten(Code), "foo", [String], []) of
{ok, _, {[Type], _}, [Arg]} ->
io:format("Type ~p~n", [Type]),
Data = encode(Arg),