split coerce/3 into two functions
Also renamed coerce_bindings to erlang_args_to_fate, to match.
This commit is contained in:
parent
d2163c1ff8
commit
3da9bd570b
@ -716,7 +716,7 @@ decode_bytearray_fate(EncodedStr) ->
|
|||||||
decode_bytearray(Type, EncodedStr) ->
|
decode_bytearray(Type, EncodedStr) ->
|
||||||
case decode_bytearray_fate(EncodedStr) of
|
case decode_bytearray_fate(EncodedStr) of
|
||||||
{ok, none} -> {ok, none};
|
{ok, none} -> {ok, none};
|
||||||
{ok, Object} -> hz_aaci:coerce(Type, Object, from_fate);
|
{ok, Object} -> hz_aaci:fate_to_erlang(Type, Object);
|
||||||
{error, Reason} -> {error, Reason}
|
{error, Reason} -> {error, Reason}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
@ -1518,7 +1518,7 @@ encode_call_data({aaci, Label}, Fun, Args) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
encode_call_data2(ArgDef, Fun, Args) ->
|
encode_call_data2(ArgDef, Fun, Args) ->
|
||||||
case hz_aaci:coerce_bindings(ArgDef, Args, to_fate) of
|
case hz_aaci:erlang_args_to_fate(ArgDef, Args) of
|
||||||
{ok, Coerced} -> gmb_fate_abi:create_calldata(Fun, Coerced);
|
{ok, Coerced} -> gmb_fate_abi:create_calldata(Fun, Coerced);
|
||||||
Errors -> Errors
|
Errors -> Errors
|
||||||
end.
|
end.
|
||||||
|
|||||||
365
src/hz_aaci.erl
365
src/hz_aaci.erl
@ -18,8 +18,9 @@
|
|||||||
% Contract call and serialization interface functions
|
% Contract call and serialization interface functions
|
||||||
-export([prepare_contract/1,
|
-export([prepare_contract/1,
|
||||||
prepare_aaci/1,
|
prepare_aaci/1,
|
||||||
coerce/3,
|
erlang_to_fate/2,
|
||||||
coerce_bindings/3,
|
fate_to_erlang/2,
|
||||||
|
erlang_args_to_fate/2,
|
||||||
aaci_get_function_signature/2]).
|
aaci_get_function_signature/2]).
|
||||||
|
|
||||||
%%% Types
|
%%% Types
|
||||||
@ -441,97 +442,51 @@ substitute_opaque_types(Bindings, Types) ->
|
|||||||
Each = fun(Type) -> substitute_opaque_type(Bindings, Type) end,
|
Each = fun(Type) -> substitute_opaque_type(Bindings, Type) end,
|
||||||
lists:map(Each, Types).
|
lists:map(Each, Types).
|
||||||
|
|
||||||
%%% Coerce
|
%%% Erlang to FATE
|
||||||
|
|
||||||
coerce_bindings(VarTypes, Terms, Direction) ->
|
erlang_args_to_fate(VarTypes, Terms) ->
|
||||||
DefLength = length(VarTypes),
|
DefLength = length(VarTypes),
|
||||||
ArgLength = length(Terms),
|
ArgLength = length(Terms),
|
||||||
if
|
if
|
||||||
DefLength =:= ArgLength -> coerce_zipped_bindings(lists:zip(VarTypes, Terms), Direction, arg);
|
DefLength =:= ArgLength -> coerce_zipped_bindings(lists:zip(VarTypes, Terms), to_fate, arg);
|
||||||
DefLength > ArgLength -> {error, too_few_args};
|
DefLength > ArgLength -> {error, too_few_args};
|
||||||
DefLength < ArgLength -> {error, too_many_args}
|
DefLength < ArgLength -> {error, too_many_args}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
coerce_zipped_bindings(Bindings, Direction, Tag) ->
|
erlang_to_fate({_, _, integer}, S) when is_integer(S) ->
|
||||||
coerce_zipped_bindings(Bindings, Direction, Tag, [], []).
|
|
||||||
|
|
||||||
coerce_zipped_bindings([Next | Rest], Direction, Tag, Good, Broken) ->
|
|
||||||
{{ArgName, Type}, Term} = Next,
|
|
||||||
case coerce(Type, Term, Direction) of
|
|
||||||
{ok, NewTerm} ->
|
|
||||||
coerce_zipped_bindings(Rest, Direction, Tag, [NewTerm | Good], Broken);
|
|
||||||
{error, Errors} ->
|
|
||||||
Wrapped = wrap_errors({Tag, ArgName}, Errors),
|
|
||||||
coerce_zipped_bindings(Rest, Direction, Tag, Good, [Wrapped | Broken])
|
|
||||||
end;
|
|
||||||
coerce_zipped_bindings([], _, _, Good, []) ->
|
|
||||||
{ok, lists:reverse(Good)};
|
|
||||||
coerce_zipped_bindings([], _, _, _, Broken) ->
|
|
||||||
{error, combine_errors(Broken)}.
|
|
||||||
|
|
||||||
wrap_errors(Location, Errors) ->
|
|
||||||
F = fun({Error, Path}) ->
|
|
||||||
{Error, [Location | Path]}
|
|
||||||
end,
|
|
||||||
lists:map(F, Errors).
|
|
||||||
|
|
||||||
combine_errors(Broken) ->
|
|
||||||
F = fun(NextErrors, Acc) ->
|
|
||||||
NextErrors ++ Acc
|
|
||||||
end,
|
|
||||||
lists:foldl(F, [], Broken).
|
|
||||||
|
|
||||||
coerce({_, _, integer}, S, _) when is_integer(S) ->
|
|
||||||
{ok, S};
|
{ok, S};
|
||||||
coerce({O, N, integer}, S, to_fate) when is_list(S) ->
|
erlang_to_fate({O, N, integer}, S) when is_list(S) ->
|
||||||
try
|
try
|
||||||
Val = list_to_integer(S),
|
Val = list_to_integer(S),
|
||||||
{ok, Val}
|
{ok, Val}
|
||||||
catch
|
catch
|
||||||
error:badarg -> single_error({invalid, O, N, S})
|
error:badarg -> single_error({invalid, O, N, S})
|
||||||
end;
|
end;
|
||||||
coerce({O, N, address}, S, to_fate) ->
|
erlang_to_fate({O, N, address}, S) ->
|
||||||
coerce_chain_object(O, N, address, account_pubkey, S);
|
coerce_chain_object(O, N, address, account_pubkey, S);
|
||||||
coerce({_, _, address}, {address, Bin}, from_fate) ->
|
erlang_to_fate({O, N, contract}, S) ->
|
||||||
Address = gmser_api_encoder:encode(account_pubkey, Bin),
|
|
||||||
{ok, unicode:characters_to_list(Address)};
|
|
||||||
coerce({O, N, contract}, S, to_fate) ->
|
|
||||||
coerce_chain_object(O, N, contract, contract_pubkey, S);
|
coerce_chain_object(O, N, contract, contract_pubkey, S);
|
||||||
coerce({_, _, contract}, {contract, Bin}, from_fate) ->
|
erlang_to_fate({_, _, signature}, S) when is_binary(S) andalso (byte_size(S) =:= 64) ->
|
||||||
Address = gmser_api_encoder:encode(contract_pubkey, Bin),
|
|
||||||
{ok, unicode:characters_to_list(Address)};
|
|
||||||
coerce({_, _, signature}, S, to_fate) when is_binary(S) andalso (byte_size(S) =:= 64) ->
|
|
||||||
% Usually to pass a binary in, you need to wrap it as {raw, Binary}, but
|
% Usually to pass a binary in, you need to wrap it as {raw, Binary}, but
|
||||||
% since sg_... strings OR hex blobs can be used as signatures in Sophia, we
|
% since sg_... strings OR hex blobs can be used as signatures in Sophia, we
|
||||||
% special case this case based on the length. Even if a binary starts with
|
% special case this case based on the length. Even if a binary starts with
|
||||||
% "sg_", 64 characters is not enough to represent a 64 byte signature, so
|
% "sg_", 64 characters is not enough to represent a 64 byte signature, so
|
||||||
% the most optimistic interpretation is to use the binary directly.
|
% the most optimistic interpretation is to use the binary directly.
|
||||||
{ok, S};
|
{ok, S};
|
||||||
coerce({O, N, signature}, S, to_fate) ->
|
erlang_to_fate({O, N, signature}, S) ->
|
||||||
coerce_chain_object(O, N, signature, signature, S);
|
coerce_chain_object(O, N, signature, signature, S);
|
||||||
coerce({_, _, signature}, Bin, from_fate) ->
|
%erlang_to_fate({_, _, channel}, S) when is_binary(S) ->
|
||||||
Address = gmser_api_encoder:encode(signature, Bin),
|
|
||||||
{ok, unicode:characters_to_list(Address)};
|
|
||||||
%coerce({_, _, channel}, S, to_fate) when is_binary(S) ->
|
|
||||||
%{ok, {channel, S}};
|
%{ok, {channel, S}};
|
||||||
%coerce({_, _, channel}, {channel, S}, from_fate) when is_binary(S) ->
|
erlang_to_fate({_, _, boolean}, true) ->
|
||||||
%{ok, S};
|
|
||||||
coerce({_, _, boolean}, true, _) ->
|
|
||||||
{ok, true};
|
{ok, true};
|
||||||
coerce({_, _, boolean}, "true", _) ->
|
erlang_to_fate({_, _, boolean}, "true") ->
|
||||||
{ok, true};
|
{ok, true};
|
||||||
coerce({_, _, boolean}, false, _) ->
|
erlang_to_fate({_, _, boolean}, false) ->
|
||||||
{ok, false};
|
{ok, false};
|
||||||
coerce({_, _, boolean}, "false", _) ->
|
erlang_to_fate({_, _, boolean}, "false") ->
|
||||||
{ok, false};
|
{ok, false};
|
||||||
coerce({O, N, boolean}, S, _) ->
|
erlang_to_fate({O, N, string}, Str) ->
|
||||||
single_error({invalid, O, N, S});
|
case unicode:characters_to_binary(Str) of
|
||||||
coerce({O, N, string}, Str, Direction) ->
|
|
||||||
Result = case Direction of
|
|
||||||
to_fate -> unicode:characters_to_binary(Str);
|
|
||||||
from_fate -> unicode:characters_to_list(Str)
|
|
||||||
end,
|
|
||||||
case Result of
|
|
||||||
{error, _, _} ->
|
{error, _, _} ->
|
||||||
single_error({invalid, O, N, Str});
|
single_error({invalid, O, N, Str});
|
||||||
{incomplete, _, _} ->
|
{incomplete, _, _} ->
|
||||||
@ -539,9 +494,9 @@ coerce({O, N, string}, Str, Direction) ->
|
|||||||
StrBin ->
|
StrBin ->
|
||||||
{ok, StrBin}
|
{ok, StrBin}
|
||||||
end;
|
end;
|
||||||
coerce({_, _, char}, Val, _Direction) when is_integer(Val) ->
|
erlang_to_fate({_, _, char}, Val) when is_integer(Val) ->
|
||||||
{ok, Val};
|
{ok, Val};
|
||||||
coerce({O, N, char}, Str, to_fate) ->
|
erlang_to_fate({O, N, char}, Str) ->
|
||||||
Result = unicode:characters_to_list(Str),
|
Result = unicode:characters_to_list(Str),
|
||||||
case Result of
|
case Result of
|
||||||
{error, _, _} ->
|
{error, _, _} ->
|
||||||
@ -553,27 +508,24 @@ coerce({O, N, char}, Str, to_fate) ->
|
|||||||
_ ->
|
_ ->
|
||||||
single_error({invalid, O, N, Str})
|
single_error({invalid, O, N, Str})
|
||||||
end;
|
end;
|
||||||
coerce({O, N, {bytes, [Count]}}, Bytes, _Direction) when is_bitstring(Bytes) ->
|
erlang_to_fate({O, N, {bytes, [Count]}}, Bytes) when is_bitstring(Bytes) ->
|
||||||
coerce_bytes(O, N, Count, Bytes);
|
coerce_bytes(O, N, Count, Bytes);
|
||||||
coerce({_, _, bits}, {bits, Num}, from_fate) ->
|
erlang_to_fate({_, _, bits}, Num) when is_integer(Num) ->
|
||||||
{ok, Num};
|
|
||||||
coerce({_, _, bits}, Num, to_fate) when is_integer(Num) ->
|
|
||||||
{ok, {bits, Num}};
|
{ok, {bits, Num}};
|
||||||
coerce({_, _, bits}, Bits, to_fate) when is_bitstring(Bits) ->
|
erlang_to_fate({_, _, bits}, Bits) when is_bitstring(Bits) ->
|
||||||
Size = bit_size(Bits),
|
Size = bit_size(Bits),
|
||||||
<<IntValue:Size>> = Bits,
|
<<IntValue:Size>> = Bits,
|
||||||
{ok, {bits, IntValue}};
|
{ok, {bits, IntValue}};
|
||||||
coerce({_, _, {list, [Type]}}, Data, Direction) when is_list(Data) ->
|
erlang_to_fate({_, _, {list, [Type]}}, Data) when is_list(Data) ->
|
||||||
coerce_list(Type, Data, Direction);
|
coerce_list(Type, Data, to_fate);
|
||||||
coerce({_, _, {map, [KeyType, ValType]}}, Data, Direction) when is_map(Data) ->
|
erlang_to_fate({_, _, {map, [KeyType, ValType]}}, Data) when is_map(Data) ->
|
||||||
coerce_map(KeyType, ValType, Data, Direction);
|
coerce_map(KeyType, ValType, Data, to_fate);
|
||||||
coerce({O, N, {tuple, ElementTypes}}, Data, to_fate) when is_tuple(Data) ->
|
erlang_to_fate({O, N, {tuple, ElementTypes}}, Data) when is_tuple(Data) ->
|
||||||
ElementList = tuple_to_list(Data),
|
ElementList = tuple_to_list(Data),
|
||||||
coerce_tuple(O, N, ElementTypes, ElementList, to_fate);
|
coerce_tuple(O, N, ElementTypes, ElementList, to_fate);
|
||||||
coerce({O, N, {tuple, ElementTypes}}, {tuple, Data}, from_fate) ->
|
erlang_to_fate({O, N, {variant, Variants}}, Name) when is_list(Name) ->
|
||||||
ElementList = tuple_to_list(Data),
|
erlang_to_fate({O, N, {variant, Variants}}, {Name});
|
||||||
coerce_tuple(O, N, ElementTypes, ElementList, from_fate);
|
erlang_to_fate({O, N, {variant, Variants}}, Data) when is_tuple(Data), tuple_size(Data) > 0 ->
|
||||||
coerce({O, N, {variant, Variants}}, Data, to_fate) when is_tuple(Data), tuple_size(Data) > 0 ->
|
|
||||||
[Name | Terms] = tuple_to_list(Data),
|
[Name | Terms] = tuple_to_list(Data),
|
||||||
case lookup_variant(Name, Variants) of
|
case lookup_variant(Name, Variants) of
|
||||||
{Tag, TermTypes} ->
|
{Tag, TermTypes} ->
|
||||||
@ -582,17 +534,9 @@ coerce({O, N, {variant, Variants}}, Data, to_fate) when is_tuple(Data), tuple_si
|
|||||||
ValidNames = [Valid || {Valid, _} <- Variants],
|
ValidNames = [Valid || {Valid, _} <- Variants],
|
||||||
single_error({invalid_variant, O, N, Name, ValidNames})
|
single_error({invalid_variant, O, N, Name, ValidNames})
|
||||||
end;
|
end;
|
||||||
coerce({O, N, {variant, Variants}}, Name, to_fate) when is_list(Name) ->
|
erlang_to_fate({O, N, {record, MemberTypes}}, Map) when is_map(Map) ->
|
||||||
coerce({O, N, {variant, Variants}}, {Name}, to_fate);
|
|
||||||
coerce({O, N, {variant, Variants}}, {variant, _, Tag, Tuple}, from_fate) ->
|
|
||||||
Terms = tuple_to_list(Tuple),
|
|
||||||
{Name, TermTypes} = lists:nth(Tag + 1, Variants),
|
|
||||||
coerce_variant2(O, N, Variants, Name, Tag, TermTypes, Terms, from_fate);
|
|
||||||
coerce({O, N, {record, MemberTypes}}, Map, to_fate) when is_map(Map) ->
|
|
||||||
coerce_map_to_record(O, N, MemberTypes, Map);
|
coerce_map_to_record(O, N, MemberTypes, Map);
|
||||||
coerce({O, N, {record, MemberTypes}}, {tuple, Tuple}, from_fate) ->
|
erlang_to_fate({O, N, {unknown_type, _}}, Data) ->
|
||||||
coerce_record_to_map(O, N, MemberTypes, Tuple);
|
|
||||||
coerce({O, N, {unknown_type, _}}, Data, _) ->
|
|
||||||
case N of
|
case N of
|
||||||
already_normalized ->
|
already_normalized ->
|
||||||
Message = "Warning: Unknown type ~p. Using term ~p as is.~n",
|
Message = "Warning: Unknown type ~p. Using term ~p as is.~n",
|
||||||
@ -602,24 +546,7 @@ coerce({O, N, {unknown_type, _}}, Data, _) ->
|
|||||||
io:format(Message, [O, N, Data])
|
io:format(Message, [O, N, Data])
|
||||||
end,
|
end,
|
||||||
{ok, Data};
|
{ok, Data};
|
||||||
coerce({O, N, _}, Data, from_fate) ->
|
erlang_to_fate({O, N, _}, Data) -> single_error({invalid, O, N, Data}).
|
||||||
case N of
|
|
||||||
already_normalized ->
|
|
||||||
io:format("Warning: Unimplemented type ~p.~nUsing term as is:~n~p~n", [O, Data]);
|
|
||||||
_ ->
|
|
||||||
io:format("Warning: Unimplemented type ~p (i.e. ~p).~nUsing term as is:~n~p~n", [O, N, Data])
|
|
||||||
end,
|
|
||||||
{ok, Data};
|
|
||||||
coerce({O, N, _}, Data, _) -> single_error({invalid, O, N, Data}).
|
|
||||||
|
|
||||||
coerce_bytes(O, N, _, Bytes) when bit_size(Bytes) rem 8 /= 0 ->
|
|
||||||
single_error({partial_bytes, O, N, bit_size(Bytes)});
|
|
||||||
coerce_bytes(_, _, any, Bytes) ->
|
|
||||||
{ok, Bytes};
|
|
||||||
coerce_bytes(O, N, Count, Bytes) when byte_size(Bytes) /= Count ->
|
|
||||||
single_error({incorrect_size, O, N, Bytes});
|
|
||||||
coerce_bytes(_, _, _, Bytes) ->
|
|
||||||
{ok, Bytes}.
|
|
||||||
|
|
||||||
coerce_chain_object(_, _, _, _, {raw, Binary}) ->
|
coerce_chain_object(_, _, _, _, {raw, Binary}) ->
|
||||||
{ok, Binary};
|
{ok, Binary};
|
||||||
@ -644,12 +571,38 @@ decode_chain_object(Tag, S) ->
|
|||||||
error:incorrect_size -> {error, incorrect_size}
|
error:incorrect_size -> {error, incorrect_size}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
coerce_bytes(O, N, _, Bytes) when bit_size(Bytes) rem 8 /= 0 ->
|
||||||
|
single_error({partial_bytes, O, N, bit_size(Bytes)});
|
||||||
|
coerce_bytes(_, _, any, Bytes) ->
|
||||||
|
{ok, Bytes};
|
||||||
|
coerce_bytes(O, N, Count, Bytes) when byte_size(Bytes) /= Count ->
|
||||||
|
single_error({incorrect_size, O, N, Bytes});
|
||||||
|
coerce_bytes(_, _, _, Bytes) ->
|
||||||
|
{ok, Bytes}.
|
||||||
|
|
||||||
|
coerce_zipped_bindings(Bindings, Direction, Tag) ->
|
||||||
|
coerce_zipped_bindings(Bindings, Direction, Tag, [], []).
|
||||||
|
|
||||||
|
coerce_zipped_bindings([Next | Rest], Direction, Tag, Good, Broken) ->
|
||||||
|
{{ArgName, Type}, Term} = Next,
|
||||||
|
case coerce_direction(Type, Term, Direction) of
|
||||||
|
{ok, NewTerm} ->
|
||||||
|
coerce_zipped_bindings(Rest, Direction, Tag, [NewTerm | Good], Broken);
|
||||||
|
{error, Errors} ->
|
||||||
|
Wrapped = wrap_errors({Tag, ArgName}, Errors),
|
||||||
|
coerce_zipped_bindings(Rest, Direction, Tag, Good, [Wrapped | Broken])
|
||||||
|
end;
|
||||||
|
coerce_zipped_bindings([], _, _, Good, []) ->
|
||||||
|
{ok, lists:reverse(Good)};
|
||||||
|
coerce_zipped_bindings([], _, _, _, Broken) ->
|
||||||
|
{error, combine_errors(Broken)}.
|
||||||
|
|
||||||
coerce_list(Type, Elements, Direction) ->
|
coerce_list(Type, Elements, Direction) ->
|
||||||
% 0 index since it represents a sophia list
|
% 0 index since it represents a sophia list
|
||||||
coerce_list(Type, Elements, Direction, 0, [], []).
|
coerce_list(Type, Elements, Direction, 0, [], []).
|
||||||
|
|
||||||
coerce_list(Type, [Next | Rest], Direction, Index, Good, Broken) ->
|
coerce_list(Type, [Next | Rest], Direction, Index, Good, Broken) ->
|
||||||
case coerce(Type, Next, Direction) of
|
case coerce_direction(Type, Next, Direction) of
|
||||||
{ok, Coerced} -> coerce_list(Type, Rest, Direction, Index + 1, [Coerced | Good], Broken);
|
{ok, Coerced} -> coerce_list(Type, Rest, Direction, Index + 1, [Coerced | Good], Broken);
|
||||||
{error, Errors} ->
|
{error, Errors} ->
|
||||||
Wrapped = wrap_errors({index, Index}, Errors),
|
Wrapped = wrap_errors({index, Index}, Errors),
|
||||||
@ -672,7 +625,7 @@ coerce_map(KeyType, ValType, Remaining, Direction, Good, Broken) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
coerce_map2(KeyType, ValType, Remaining, Direction, Good, Broken, K, V) ->
|
coerce_map2(KeyType, ValType, Remaining, Direction, Good, Broken, K, V) ->
|
||||||
case coerce(KeyType, K, Direction) of
|
case coerce_direction(KeyType, K, Direction) of
|
||||||
{ok, KFATE} ->
|
{ok, KFATE} ->
|
||||||
coerce_map3(KeyType, ValType, Remaining, Direction, Good, Broken, K, V, KFATE);
|
coerce_map3(KeyType, ValType, Remaining, Direction, Good, Broken, K, V, KFATE);
|
||||||
{error, Errors} ->
|
{error, Errors} ->
|
||||||
@ -683,7 +636,7 @@ coerce_map2(KeyType, ValType, Remaining, Direction, Good, Broken, K, V) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
coerce_map3(KeyType, ValType, Remaining, Direction, Good, Broken, K, V, KFATE) ->
|
coerce_map3(KeyType, ValType, Remaining, Direction, Good, Broken, K, V, KFATE) ->
|
||||||
case coerce(ValType, V, Direction) of
|
case coerce_direction(ValType, V, Direction) of
|
||||||
{ok, VFATE} ->
|
{ok, VFATE} ->
|
||||||
NewGood = Good#{KFATE => VFATE},
|
NewGood = Good#{KFATE => VFATE},
|
||||||
coerce_map(KeyType, ValType, Remaining, Direction, NewGood, Broken);
|
coerce_map(KeyType, ValType, Remaining, Direction, NewGood, Broken);
|
||||||
@ -720,11 +673,6 @@ coerce_tuple(O, N, TermTypes, Terms, Direction) ->
|
|||||||
Errors -> Errors
|
Errors -> Errors
|
||||||
end.
|
end.
|
||||||
|
|
||||||
% Wraps a single error in a list, along with an empty path, so that other
|
|
||||||
% accumulating error handlers can work with it.
|
|
||||||
single_error(Reason) ->
|
|
||||||
{error, [{Reason, []}]}.
|
|
||||||
|
|
||||||
coerce_variant2(O, N, Variants, Name, Tag, TermTypes, Terms, Direction) ->
|
coerce_variant2(O, N, Variants, Name, Tag, TermTypes, Terms, Direction) ->
|
||||||
% FIXME: we could go through and add the variant tag to the adt_element
|
% FIXME: we could go through and add the variant tag to the adt_element
|
||||||
% paths?
|
% paths?
|
||||||
@ -751,7 +699,7 @@ coerce_tuple_elements(Types, Terms, Direction, Tag) ->
|
|||||||
coerce_tuple_elements(Types, Terms, Direction, Tag, 0, [], []).
|
coerce_tuple_elements(Types, Terms, Direction, Tag, 0, [], []).
|
||||||
|
|
||||||
coerce_tuple_elements([Type | Types], [Term | Terms], Direction, Tag, Index, Good, Broken) ->
|
coerce_tuple_elements([Type | Types], [Term | Terms], Direction, Tag, Index, Good, Broken) ->
|
||||||
case coerce(Type, Term, Direction) of
|
case coerce_direction(Type, Term, Direction) of
|
||||||
{ok, Value} ->
|
{ok, Value} ->
|
||||||
coerce_tuple_elements(Types, Terms, Direction, Tag, Index + 1, [Value | Good], Broken);
|
coerce_tuple_elements(Types, Terms, Direction, Tag, Index + 1, [Value | Good], Broken);
|
||||||
{error, Errors} ->
|
{error, Errors} ->
|
||||||
@ -820,6 +768,91 @@ zip_record_field({Name, Type}, {Remaining, Missing}) ->
|
|||||||
{missing, {Remaining, [Name | Missing]}}
|
{missing, {Remaining, [Name | Missing]}}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
% Wraps a single error in a list, along with an empty path, so that other
|
||||||
|
% accumulating error handlers can work with it.
|
||||||
|
single_error(Reason) ->
|
||||||
|
{error, [{Reason, []}]}.
|
||||||
|
|
||||||
|
wrap_errors(Location, Errors) ->
|
||||||
|
F = fun({Error, Path}) ->
|
||||||
|
{Error, [Location | Path]}
|
||||||
|
end,
|
||||||
|
lists:map(F, Errors).
|
||||||
|
|
||||||
|
combine_errors(Broken) ->
|
||||||
|
F = fun(NextErrors, Acc) ->
|
||||||
|
NextErrors ++ Acc
|
||||||
|
end,
|
||||||
|
lists:foldl(F, [], Broken).
|
||||||
|
|
||||||
|
|
||||||
|
%%% FATE to Erlang
|
||||||
|
|
||||||
|
% Not sure if this is needed... fate_to_erlang shouldn't fail.
|
||||||
|
coerce_direction(Type, Term, to_fate) ->
|
||||||
|
erlang_to_fate(Type, Term);
|
||||||
|
coerce_direction(Type, Term, from_fate) ->
|
||||||
|
fate_to_erlang(Type, Term).
|
||||||
|
|
||||||
|
fate_to_erlang({_, _, integer}, S) when is_integer(S) ->
|
||||||
|
{ok, S};
|
||||||
|
fate_to_erlang({_, _, address}, {address, Bin}) ->
|
||||||
|
Address = gmser_api_encoder:encode(account_pubkey, Bin),
|
||||||
|
{ok, unicode:characters_to_list(Address)};
|
||||||
|
fate_to_erlang({_, _, contract}, {contract, Bin}) ->
|
||||||
|
Address = gmser_api_encoder:encode(contract_pubkey, Bin),
|
||||||
|
{ok, unicode:characters_to_list(Address)};
|
||||||
|
fate_to_erlang({_, _, signature}, Bin) ->
|
||||||
|
Address = gmser_api_encoder:encode(signature, Bin),
|
||||||
|
{ok, unicode:characters_to_list(Address)};
|
||||||
|
%fate_to_erlang({_, _, channel}, {channel, S}) when is_binary(S) ->
|
||||||
|
%{ok, S};
|
||||||
|
fate_to_erlang({_, _, boolean}, true) ->
|
||||||
|
{ok, true};
|
||||||
|
fate_to_erlang({_, _, boolean}, false) ->
|
||||||
|
{ok, false};
|
||||||
|
fate_to_erlang({_, _, string}, Bin) ->
|
||||||
|
Str = binary_to_list(Bin),
|
||||||
|
{ok, Str};
|
||||||
|
fate_to_erlang({_, _, char}, Val) ->
|
||||||
|
{ok, Val};
|
||||||
|
fate_to_erlang({O, N, {bytes, [Count]}}, Bytes) when is_bitstring(Bytes) ->
|
||||||
|
coerce_bytes(O, N, Count, Bytes);
|
||||||
|
fate_to_erlang({_, _, bits}, {bits, Num}) ->
|
||||||
|
{ok, Num};
|
||||||
|
fate_to_erlang({_, _, {list, [Type]}}, Data) when is_list(Data) ->
|
||||||
|
coerce_list(Type, Data, from_fate);
|
||||||
|
fate_to_erlang({_, _, {map, [KeyType, ValType]}}, Data) when is_map(Data) ->
|
||||||
|
coerce_map(KeyType, ValType, Data, from_fate);
|
||||||
|
fate_to_erlang({O, N, {tuple, ElementTypes}}, {tuple, Data}) ->
|
||||||
|
ElementList = tuple_to_list(Data),
|
||||||
|
coerce_tuple(O, N, ElementTypes, ElementList, from_fate);
|
||||||
|
fate_to_erlang({O, N, {variant, Variants}}, {variant, _, Tag, Tuple}) ->
|
||||||
|
Terms = tuple_to_list(Tuple),
|
||||||
|
{Name, TermTypes} = lists:nth(Tag + 1, Variants),
|
||||||
|
coerce_variant2(O, N, Variants, Name, Tag, TermTypes, Terms, from_fate);
|
||||||
|
fate_to_erlang({O, N, {record, MemberTypes}}, {tuple, Tuple}) ->
|
||||||
|
coerce_record_to_map(O, N, MemberTypes, Tuple);
|
||||||
|
fate_to_erlang({O, N, {unknown_type, _}}, Data) ->
|
||||||
|
case N of
|
||||||
|
already_normalized ->
|
||||||
|
Message = "Warning: Unknown type ~p. Using term ~p as is.~n",
|
||||||
|
io:format(Message, [O, Data]);
|
||||||
|
_ ->
|
||||||
|
Message = "Warning: Unknown type ~p (i.e. ~p). Using term ~p as is.~n",
|
||||||
|
io:format(Message, [O, N, Data])
|
||||||
|
end,
|
||||||
|
{ok, Data};
|
||||||
|
fate_to_erlang({O, N, _}, Data) ->
|
||||||
|
case N of
|
||||||
|
already_normalized ->
|
||||||
|
io:format("Warning: Unimplemented type ~p.~nUsing term as is:~n~p~n", [O, Data]);
|
||||||
|
_ ->
|
||||||
|
io:format("Warning: Unimplemented type ~p (i.e. ~p).~nUsing term as is:~n~p~n", [O, N, Data])
|
||||||
|
end,
|
||||||
|
{ok, Data}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%%% AACI Getters
|
%%% AACI Getters
|
||||||
|
|
||||||
@ -841,38 +874,44 @@ aaci_get_function_signature({aaci, _, FunDefs, _}, Fun) ->
|
|||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
%%% Simple coerce/3 tests
|
%%% Simple FATE/erlang tests
|
||||||
|
|
||||||
% Round trip coerce run for the eunit tests below. If these results don't match
|
check_erlang_to_fate(Type, Sophia, Fate) ->
|
||||||
% then the test should fail.
|
{ok, FateActual} = erlang_to_fate(Type, Sophia),
|
||||||
try_coerce(Type, Sophia, Fate) ->
|
|
||||||
% Run both first, to see if they fail to produce any result.
|
|
||||||
{ok, FateActual} = coerce(Type, Sophia, to_fate),
|
|
||||||
{ok, SophiaActual} = coerce(Type, Fate, from_fate),
|
|
||||||
% Now check that the results were what we expected.
|
|
||||||
case FateActual of
|
case FateActual of
|
||||||
Fate ->
|
Fate ->
|
||||||
ok;
|
ok;
|
||||||
_ ->
|
_ ->
|
||||||
erlang:error({to_fate_failed, Fate, FateActual})
|
erlang:error({to_fate_failed, Fate, FateActual})
|
||||||
end,
|
end.
|
||||||
|
|
||||||
|
check_fate_to_erlang(Type, Fate, Sophia) ->
|
||||||
|
{ok, SophiaActual} = fate_to_erlang(Type, Fate),
|
||||||
|
% Now check that the results were what we expected.
|
||||||
case SophiaActual of
|
case SophiaActual of
|
||||||
Sophia ->
|
Sophia ->
|
||||||
ok;
|
ok;
|
||||||
_ ->
|
_ ->
|
||||||
erlang:error({from_fate_failed, Sophia, SophiaActual})
|
erlang:error({from_fate_failed, Sophia, SophiaActual})
|
||||||
end,
|
end.
|
||||||
|
|
||||||
|
% Round trip coerce run for the eunit tests below. If these results don't match
|
||||||
|
% then the test should fail.
|
||||||
|
check_roundtrip(Type, Sophia, Fate) ->
|
||||||
|
check_erlang_to_fate(Type, Sophia, Fate),
|
||||||
|
check_fate_to_erlang(Type, Fate, Sophia),
|
||||||
|
|
||||||
% Finally, check that the FATE result is something that gmb understands.
|
% Finally, check that the FATE result is something that gmb understands.
|
||||||
gmb_fate_encoding:serialize(Fate),
|
gmb_fate_encoding:serialize(Fate),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
coerce_int_test() ->
|
coerce_int_test() ->
|
||||||
{ok, Type} = annotate_type(integer, #{}),
|
{ok, Type} = annotate_type(integer, #{}),
|
||||||
try_coerce(Type, 123, 123).
|
check_roundtrip(Type, 123, 123).
|
||||||
|
|
||||||
coerce_address_test() ->
|
coerce_address_test() ->
|
||||||
{ok, Type} = annotate_type(address, #{}),
|
{ok, Type} = annotate_type(address, #{}),
|
||||||
try_coerce(Type,
|
check_roundtrip(Type,
|
||||||
"ak_2FTnrGfV8qsfHpaSEHpBrziioCpwwzLqSevHqfxQY3PaAAdARx",
|
"ak_2FTnrGfV8qsfHpaSEHpBrziioCpwwzLqSevHqfxQY3PaAAdARx",
|
||||||
{address, <<164,136,155,90,124,22,40,206,255,76,213,56,238,123,
|
{address, <<164,136,155,90,124,22,40,206,255,76,213,56,238,123,
|
||||||
167,208,53,78,40,235,2,163,132,36,47,183,228,151,9,
|
167,208,53,78,40,235,2,163,132,36,47,183,228,151,9,
|
||||||
@ -880,7 +919,7 @@ coerce_address_test() ->
|
|||||||
|
|
||||||
coerce_contract_test() ->
|
coerce_contract_test() ->
|
||||||
{ok, Type} = annotate_type(contract, #{}),
|
{ok, Type} = annotate_type(contract, #{}),
|
||||||
try_coerce(Type,
|
check_roundtrip(Type,
|
||||||
"ct_2FTnrGfV8qsfHpaSEHpBrziioCpwwzLqSevHqfxQY3PaAAdARx",
|
"ct_2FTnrGfV8qsfHpaSEHpBrziioCpwwzLqSevHqfxQY3PaAAdARx",
|
||||||
{contract, <<164,136,155,90,124,22,40,206,255,76,213,56,238,123,
|
{contract, <<164,136,155,90,124,22,40,206,255,76,213,56,238,123,
|
||||||
167,208,53,78,40,235,2,163,132,36,47,183,228,151,9,
|
167,208,53,78,40,235,2,163,132,36,47,183,228,151,9,
|
||||||
@ -888,7 +927,7 @@ coerce_contract_test() ->
|
|||||||
|
|
||||||
coerce_signature_test() ->
|
coerce_signature_test() ->
|
||||||
{ok, Type} = annotate_type(signature, #{}),
|
{ok, Type} = annotate_type(signature, #{}),
|
||||||
try_coerce(Type,
|
check_roundtrip(Type,
|
||||||
"sg_XDyF8LJC4tpMyAySvpaG1f5V9F2XxAbRx9iuVjvvdNMwVracLhzAuXhRM5kXAFtpwW1DCHuz5jGehUayCah4jub32Ti2n",
|
"sg_XDyF8LJC4tpMyAySvpaG1f5V9F2XxAbRx9iuVjvvdNMwVracLhzAuXhRM5kXAFtpwW1DCHuz5jGehUayCah4jub32Ti2n",
|
||||||
<<231,4,97,129,16,173,37,42,194,249,28,94,134,163,208,84,22,135,
|
<<231,4,97,129,16,173,37,42,194,249,28,94,134,163,208,84,22,135,
|
||||||
169,85,212,142,14,12,233,252,97,50,193,158,229,51,123,206,222,
|
169,85,212,142,14,12,233,252,97,50,193,158,229,51,123,206,222,
|
||||||
@ -901,69 +940,69 @@ coerce_signature_binary_test() ->
|
|||||||
169,85,212,142,14,12,233,252,97,50,193,158,229,51,123,206,222,
|
169,85,212,142,14,12,233,252,97,50,193,158,229,51,123,206,222,
|
||||||
249,2,3,85,173,106,150,243,253,89,128,248,52,195,140,95,114,
|
249,2,3,85,173,106,150,243,253,89,128,248,52,195,140,95,114,
|
||||||
233,110,119,143,206,137,124,36,63,154,85,7>>,
|
233,110,119,143,206,137,124,36,63,154,85,7>>,
|
||||||
{ok, Binary} = coerce(Type, {raw, Binary}, to_fate),
|
{ok, Binary} = erlang_to_fate(Type, {raw, Binary}),
|
||||||
{ok, Binary} = coerce(Type, Binary, to_fate),
|
{ok, Binary} = erlang_to_fate(Type, Binary),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
coerce_bool_test() ->
|
coerce_bool_test() ->
|
||||||
{ok, Type} = annotate_type(boolean, #{}),
|
{ok, Type} = annotate_type(boolean, #{}),
|
||||||
try_coerce(Type, true, true),
|
check_roundtrip(Type, true, true),
|
||||||
try_coerce(Type, false, false).
|
check_roundtrip(Type, false, false).
|
||||||
|
|
||||||
coerce_string_test() ->
|
coerce_string_test() ->
|
||||||
{ok, Type} = annotate_type(string, #{}),
|
{ok, Type} = annotate_type(string, #{}),
|
||||||
try_coerce(Type, "hello world", <<"hello world">>).
|
check_roundtrip(Type, "hello world", <<"hello world">>).
|
||||||
|
|
||||||
coerce_list_test() ->
|
coerce_list_test() ->
|
||||||
{ok, Type} = annotate_type({list, [string]}, #{}),
|
{ok, Type} = annotate_type({list, [string]}, #{}),
|
||||||
try_coerce(Type, ["hello world", [65, 32, 65]], [<<"hello world">>, <<65, 32, 65>>]).
|
check_roundtrip(Type, ["hello world", [65, 32, 65]], [<<"hello world">>, <<65, 32, 65>>]).
|
||||||
|
|
||||||
coerce_map_test() ->
|
coerce_map_test() ->
|
||||||
{ok, Type} = annotate_type({map, [string, {list, [integer]}]}, #{}),
|
{ok, Type} = annotate_type({map, [string, {list, [integer]}]}, #{}),
|
||||||
try_coerce(Type, #{"a" => "a", "b" => "b"}, #{<<"a">> => "a", <<"b">> => "b"}).
|
check_roundtrip(Type, #{"a" => "a", "b" => "b"}, #{<<"a">> => "a", <<"b">> => "b"}).
|
||||||
|
|
||||||
coerce_tuple_test() ->
|
coerce_tuple_test() ->
|
||||||
{ok, Type} = annotate_type({tuple, [integer, string]}, #{}),
|
{ok, Type} = annotate_type({tuple, [integer, string]}, #{}),
|
||||||
try_coerce(Type, {123, "456"}, {tuple, {123, <<"456">>}}).
|
check_roundtrip(Type, {123, "456"}, {tuple, {123, <<"456">>}}).
|
||||||
|
|
||||||
coerce_variant_test() ->
|
coerce_variant_test() ->
|
||||||
{ok, Type} = annotate_type({variant, [{"A", [integer]},
|
{ok, Type} = annotate_type({variant, [{"A", [integer]},
|
||||||
{"B", [integer, integer]}]},
|
{"B", [integer, integer]}]},
|
||||||
#{}),
|
#{}),
|
||||||
try_coerce(Type, {"A", 123}, {variant, [1, 2], 0, {123}}),
|
check_roundtrip(Type, {"A", 123}, {variant, [1, 2], 0, {123}}),
|
||||||
try_coerce(Type, {"B", 456, 789}, {variant, [1, 2], 1, {456, 789}}).
|
check_roundtrip(Type, {"B", 456, 789}, {variant, [1, 2], 1, {456, 789}}).
|
||||||
|
|
||||||
coerce_option_test() ->
|
coerce_option_test() ->
|
||||||
{ok, Type} = annotate_type({"option", [integer]}, builtin_typedefs()),
|
{ok, Type} = annotate_type({"option", [integer]}, builtin_typedefs()),
|
||||||
try_coerce(Type, {"None"}, {variant, [0, 1], 0, {}}),
|
check_roundtrip(Type, {"None"}, {variant, [0, 1], 0, {}}),
|
||||||
try_coerce(Type, {"Some", 1}, {variant, [0, 1], 1, {1}}).
|
check_roundtrip(Type, {"Some", 1}, {variant, [0, 1], 1, {1}}).
|
||||||
|
|
||||||
coerce_record_test() ->
|
coerce_record_test() ->
|
||||||
{ok, Type} = annotate_type({record, [{"a", integer}, {"b", integer}]}, #{}),
|
{ok, Type} = annotate_type({record, [{"a", integer}, {"b", integer}]}, #{}),
|
||||||
try_coerce(Type, #{"a" => 123, "b" => 456}, {tuple, {123, 456}}).
|
check_roundtrip(Type, #{"a" => 123, "b" => 456}, {tuple, {123, 456}}).
|
||||||
|
|
||||||
coerce_bytes_test() ->
|
coerce_bytes_test() ->
|
||||||
{ok, Type} = annotate_type({tuple, [{bytes, [4]}, {bytes, [any]}]}, #{}),
|
{ok, Type} = annotate_type({tuple, [{bytes, [4]}, {bytes, [any]}]}, #{}),
|
||||||
try_coerce(Type, {<<"abcd">>, <<"efghi">>}, {tuple, {<<"abcd">>, <<"efghi">>}}).
|
check_roundtrip(Type, {<<"abcd">>, <<"efghi">>}, {tuple, {<<"abcd">>, <<"efghi">>}}).
|
||||||
|
|
||||||
coerce_bits_test() ->
|
coerce_bits_test() ->
|
||||||
{ok, Type} = annotate_type(bits, #{}),
|
{ok, Type} = annotate_type(bits, #{}),
|
||||||
try_coerce(Type, 5, {bits, 5}).
|
check_roundtrip(Type, 5, {bits, 5}).
|
||||||
|
|
||||||
coerce_char_test() ->
|
coerce_char_test() ->
|
||||||
{ok, Type} = annotate_type(char, #{}),
|
{ok, Type} = annotate_type(char, #{}),
|
||||||
try_coerce(Type, $?, $?).
|
check_roundtrip(Type, $?, $?).
|
||||||
|
|
||||||
coerce_unicode_test() ->
|
coerce_unicode_test() ->
|
||||||
{ok, Type} = annotate_type(char, #{}),
|
{ok, Type} = annotate_type(char, #{}),
|
||||||
% Latin Small Letter C with cedilla and acute
|
% Latin Small Letter C with cedilla and acute
|
||||||
{ok, $ḉ} = coerce(Type, <<"ḉ"/utf8>>, to_fate),
|
{ok, $ḉ} = erlang_to_fate(Type, <<"ḉ"/utf8>>),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
coerce_hash_test() ->
|
coerce_hash_test() ->
|
||||||
{ok, Type} = annotate_type("hash", builtin_typedefs()),
|
{ok, Type} = annotate_type("hash", builtin_typedefs()),
|
||||||
Hash = list_to_binary(lists:seq(1,32)),
|
Hash = list_to_binary(lists:seq(1,32)),
|
||||||
try_coerce(Type, Hash, Hash),
|
check_roundtrip(Type, Hash, Hash),
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
|
||||||
@ -985,7 +1024,7 @@ namespace_coerce_test() ->
|
|||||||
",
|
",
|
||||||
{ok, AACI} = aaci_from_string(Contract),
|
{ok, AACI} = aaci_from_string(Contract),
|
||||||
{ok, {[], Output}} = aaci_get_function_signature(AACI, "f"),
|
{ok, {[], Output}} = aaci_get_function_signature(AACI, "f"),
|
||||||
try_coerce(Output, #{"a" => 123, "b" => 456}, {tuple, {123, 456}}).
|
check_roundtrip(Output, #{"a" => 123, "b" => 456}, {tuple, {123, 456}}).
|
||||||
|
|
||||||
record_substitution_test() ->
|
record_substitution_test() ->
|
||||||
Contract = "
|
Contract = "
|
||||||
@ -995,7 +1034,7 @@ record_substitution_test() ->
|
|||||||
",
|
",
|
||||||
{ok, AACI} = aaci_from_string(Contract),
|
{ok, AACI} = aaci_from_string(Contract),
|
||||||
{ok, {[], Output}} = aaci_get_function_signature(AACI, "f"),
|
{ok, {[], Output}} = aaci_get_function_signature(AACI, "f"),
|
||||||
try_coerce(Output, #{"a" => 123, "b" => 456}, {tuple, {123, 456}}).
|
check_roundtrip(Output, #{"a" => 123, "b" => 456}, {tuple, {123, 456}}).
|
||||||
|
|
||||||
tuple_substitution_test() ->
|
tuple_substitution_test() ->
|
||||||
Contract = "
|
Contract = "
|
||||||
@ -1005,7 +1044,7 @@ tuple_substitution_test() ->
|
|||||||
",
|
",
|
||||||
{ok, AACI} = aaci_from_string(Contract),
|
{ok, AACI} = aaci_from_string(Contract),
|
||||||
{ok, {[], Output}} = aaci_get_function_signature(AACI, "f"),
|
{ok, {[], Output}} = aaci_get_function_signature(AACI, "f"),
|
||||||
try_coerce(Output, {1, 2, "hello"}, {tuple, {1, 2, <<"hello">>}}).
|
check_roundtrip(Output, {1, 2, "hello"}, {tuple, {1, 2, <<"hello">>}}).
|
||||||
|
|
||||||
variant_substitution_test() ->
|
variant_substitution_test() ->
|
||||||
Contract = "
|
Contract = "
|
||||||
@ -1015,8 +1054,8 @@ variant_substitution_test() ->
|
|||||||
",
|
",
|
||||||
{ok, AACI} = aaci_from_string(Contract),
|
{ok, AACI} = aaci_from_string(Contract),
|
||||||
{ok, {[], Output}} = aaci_get_function_signature(AACI, "f"),
|
{ok, {[], Output}} = aaci_get_function_signature(AACI, "f"),
|
||||||
try_coerce(Output, {"Left", "hi", 1}, {variant, [2, 2], 0, {<<"hi">>, 1}}),
|
check_roundtrip(Output, {"Left", "hi", 1}, {variant, [2, 2], 0, {<<"hi">>, 1}}),
|
||||||
try_coerce(Output, {"Right", 2, 3}, {variant, [2, 2], 1, {2, 3}}).
|
check_roundtrip(Output, {"Right", 2, 3}, {variant, [2, 2], 1, {2, 3}}).
|
||||||
|
|
||||||
nested_coerce_test() ->
|
nested_coerce_test() ->
|
||||||
Contract = "
|
Contract = "
|
||||||
@ -1027,7 +1066,7 @@ nested_coerce_test() ->
|
|||||||
",
|
",
|
||||||
{ok, AACI} = aaci_from_string(Contract),
|
{ok, AACI} = aaci_from_string(Contract),
|
||||||
{ok, {[], Output}} = aaci_get_function_signature(AACI, "f"),
|
{ok, {[], Output}} = aaci_get_function_signature(AACI, "f"),
|
||||||
try_coerce(Output,
|
check_roundtrip(Output,
|
||||||
#{ "f1" => {1, 2}, "f2" => {"a", "b"}},
|
#{ "f1" => {1, 2}, "f2" => {"a", "b"}},
|
||||||
{tuple, {{tuple, {1, 2}}, {tuple, {<<"a">>, <<"b">>}}}}).
|
{tuple, {{tuple, {1, 2}}, {tuple, {<<"a">>, <<"b">>}}}}).
|
||||||
|
|
||||||
@ -1039,7 +1078,7 @@ state_coerce_test() ->
|
|||||||
",
|
",
|
||||||
{ok, AACI} = aaci_from_string(Contract),
|
{ok, AACI} = aaci_from_string(Contract),
|
||||||
{ok, {[], Output}} = aaci_get_function_signature(AACI, "init"),
|
{ok, {[], Output}} = aaci_get_function_signature(AACI, "init"),
|
||||||
try_coerce(Output, 0, 0).
|
check_roundtrip(Output, 0, 0).
|
||||||
|
|
||||||
param_test() ->
|
param_test() ->
|
||||||
Contract = "
|
Contract = "
|
||||||
@ -1049,8 +1088,8 @@ param_test() ->
|
|||||||
",
|
",
|
||||||
{ok, AACI} = aaci_from_string(Contract),
|
{ok, AACI} = aaci_from_string(Contract),
|
||||||
{ok, {[{"x", Input}], Output}} = aaci_get_function_signature(AACI, "init"),
|
{ok, {[{"x", Input}], Output}} = aaci_get_function_signature(AACI, "init"),
|
||||||
try_coerce(Input, 0, 0),
|
check_roundtrip(Input, 0, 0),
|
||||||
try_coerce(Output, 0, 0).
|
check_roundtrip(Output, 0, 0).
|
||||||
|
|
||||||
%%% Obscure Sophia types where we should check the AACI as well
|
%%% Obscure Sophia types where we should check the AACI as well
|
||||||
|
|
||||||
@ -1126,21 +1165,21 @@ name_coerce_test() ->
|
|||||||
{ok, TTL} = annotate_type("Chain.ttl", builtin_typedefs()),
|
{ok, TTL} = annotate_type("Chain.ttl", builtin_typedefs()),
|
||||||
TTLSoph = {"FixedTTL", 0},
|
TTLSoph = {"FixedTTL", 0},
|
||||||
TTLFate = {variant, [1, 1], 0, {0}},
|
TTLFate = {variant, [1, 1], 0, {0}},
|
||||||
try_coerce(TTL, TTLSoph, TTLFate),
|
check_roundtrip(TTL, TTLSoph, TTLFate),
|
||||||
{ok, Pointee} = annotate_type("AENS.pointee", builtin_typedefs()),
|
{ok, Pointee} = annotate_type("AENS.pointee", builtin_typedefs()),
|
||||||
PointeeSoph = {"AccountPt", AddrSoph},
|
PointeeSoph = {"AccountPt", AddrSoph},
|
||||||
PointeeFate = {variant, [1, 1, 1, 1], 0, {AddrFate}},
|
PointeeFate = {variant, [1, 1, 1, 1], 0, {AddrFate}},
|
||||||
try_coerce(Pointee, PointeeSoph, PointeeFate),
|
check_roundtrip(Pointee, PointeeSoph, PointeeFate),
|
||||||
{ok, Name} = annotate_type("AENS.name", builtin_typedefs()),
|
{ok, Name} = annotate_type("AENS.name", builtin_typedefs()),
|
||||||
NameSoph = {"Name", AddrSoph, TTLSoph, #{"myname" => PointeeSoph}},
|
NameSoph = {"Name", AddrSoph, TTLSoph, #{"myname" => PointeeSoph}},
|
||||||
NameFate = {variant, [3], 0, {AddrFate, TTLFate, #{<<"myname">> => PointeeFate}}},
|
NameFate = {variant, [3], 0, {AddrFate, TTLFate, #{<<"myname">> => PointeeFate}}},
|
||||||
try_coerce(Name, NameSoph, NameFate).
|
check_roundtrip(Name, NameSoph, NameFate).
|
||||||
|
|
||||||
void_coerce_test() ->
|
void_coerce_test() ->
|
||||||
% Void itself can't be represented, but other types built out of void are
|
% Void itself can't be represented, but other types built out of void are
|
||||||
% valid.
|
% valid.
|
||||||
{ok, NonOption} = annotate_type({"option", ["void"]}, builtin_typedefs()),
|
{ok, NonOption} = annotate_type({"option", ["void"]}, builtin_typedefs()),
|
||||||
try_coerce(NonOption, {"None"}, {variant, [0, 1], 0, {}}),
|
check_roundtrip(NonOption, {"None"}, {variant, [0, 1], 0, {}}),
|
||||||
{ok, NonList} = annotate_type({list, ["void"]}, builtin_typedefs()),
|
{ok, NonList} = annotate_type({list, ["void"]}, builtin_typedefs()),
|
||||||
try_coerce(NonList, [], []).
|
check_roundtrip(NonList, [], []).
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user