From 5a4a84805f07f47f7fd865a221d2844c4f94854a Mon Sep 17 00:00:00 2001 From: Ulf Norell Date: Tue, 26 Feb 2019 15:01:27 +0100 Subject: [PATCH] change create_calldata function to also take fun name and arguments --- src/aeso_compiler.erl | 51 +++++++++++++++++++++-------------------- test/aeso_abi_tests.erl | 12 ++++------ 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/src/aeso_compiler.erl b/src/aeso_compiler.erl index 5a841d8..dbdd5a0 100644 --- a/src/aeso_compiler.erl +++ b/src/aeso_compiler.erl @@ -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; diff --git a/test/aeso_abi_tests.erl b/test/aeso_abi_tests.erl index ae4979d..8557975 100644 --- a/test/aeso_abi_tests.erl +++ b/test/aeso_abi_tests.erl @@ -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),