New representation of variant values. #140

Merged
zxq9 merged 2 commits from PT-164597736-variant-types into master 2019-03-29 22:52:22 +09:00
8 changed files with 98 additions and 59 deletions

View File

@ -101,8 +101,8 @@ Immediate values can be of 11 types:
`()` `()`
`(1, "foo")` `(1, "foo")`
9. Variants: (| Size | Tag | ( Elements ) |) 9. Variants: (| [Arities] | Tag | ( Elements ) |)
`(| 42 | 12 | ( "foo", 12) |)` `(| [1,3,5,2] | 3 | ( "foo", 12) |)`
10. Hashes: #{base64char}+ 10. Hashes: #{base64char}+
`#AQIDCioLFQ==` `#AQIDCioLFQ==`

View File

@ -13,7 +13,7 @@
-define(FATE_ORACLE_T, {oracle, <<_:256>>}). -define(FATE_ORACLE_T, {oracle, <<_:256>>}).
-define(FATE_NAME_T, {name, <<_:256>>}). -define(FATE_NAME_T, {name, <<_:256>>}).
-define(FATE_CHANNEL_T, {channel, <<_:256>>}). -define(FATE_CHANNEL_T, {channel, <<_:256>>}).
-define(FATE_VARIANT_T, {variant, ?FATE_BYTE_T, ?FATE_BYTE_T, tuple()}). -define(FATE_VARIANT_T, {variant, [byte()], ?FATE_BYTE_T, tuple()}).
-define(FATE_VOID_T, void). -define(FATE_VOID_T, void).
-define(FATE_TUPLE_T, {tuple, tuple()}). -define(FATE_TUPLE_T, {tuple, tuple()}).
-define(FATE_BITS_T, {bits, integer()}). -define(FATE_BITS_T, {bits, integer()}).
@ -34,7 +34,7 @@
-define(IS_FATE_VARIANT(X), (is_tuple(X) -define(IS_FATE_VARIANT(X), (is_tuple(X)
andalso andalso
(variant == element(1, X) (variant == element(1, X)
andalso is_integer(element(2, X)) andalso is_list(element(2, X))
andalso is_integer(element(3, X)) andalso is_integer(element(3, X))
andalso is_tuple(element(4, X)) andalso is_tuple(element(4, X))
))). ))).
@ -71,7 +71,7 @@
-define(FATE_VOID, void). -define(FATE_VOID, void).
-define(FATE_EMPTY_STRING, <<>>). -define(FATE_EMPTY_STRING, <<>>).
-define(FATE_STRING(S), S). -define(FATE_STRING(S), S).
-define(FATE_VARIANT(Size, Tag,T), {variant, Size, Tag, T}). -define(FATE_VARIANT(Arity, Tag,T), {variant, Arity, Tag, T}).
-define(MAKE_FATE_INTEGER(X), X). -define(MAKE_FATE_INTEGER(X), X).
-define(MAKE_FATE_LIST(X), X). -define(MAKE_FATE_LIST(X), X).

View File

@ -64,8 +64,8 @@
%%% 8. Tuples ( Elements ) %%% 8. Tuples ( Elements )
%%% () %%% ()
%%% (1, "foo") %%% (1, "foo")
%%% 9. Variants: (| Size | Tag | ( Elements ) |) %%% 9. Variants: (| [Arities] | Tag | ( Elements ) |)
%%% (| 42 | 12 | ( "foo", 12) |) %%% (| [0,1,2] | 2 | ( "foo", 12) |)
%%% 10. Hashes: #{base64char}+ %%% 10. Hashes: #{base64char}+
%%% #AQIDCioLFQ== %%% #AQIDCioLFQ==
%%% 11. Signatures: $sg_{base58char}+ %%% 11. Signatures: $sg_{base58char}+
@ -808,8 +808,8 @@ to_bytecode([{'(',_line}|Rest], Address, Env, Code, Opts) ->
Tuple = aeb_fate_data:make_tuple(list_to_tuple(Elements)), Tuple = aeb_fate_data:make_tuple(list_to_tuple(Elements)),
to_bytecode(Rest2, Address, Env, [{immediate, Tuple}|Code], Opts); to_bytecode(Rest2, Address, Env, [{immediate, Tuple}|Code], Opts);
to_bytecode([{start_variant,_line}|_] = Tokens, Address, Env, Code, Opts) -> to_bytecode([{start_variant,_line}|_] = Tokens, Address, Env, Code, Opts) ->
{Size, Tag, Values, Rest} = parse_variant(Tokens), {Arities, Tag, Values, Rest} = parse_variant(Tokens),
Variant = aeb_fate_data:make_variant(Size, Tag, Values), Variant = aeb_fate_data:make_variant(Arities, Tag, Values),
to_bytecode(Rest, Address, Env, [{immediate, Variant}|Code], Opts); to_bytecode(Rest, Address, Env, [{immediate, Variant}|Code], Opts);
to_bytecode([{bits,_line, Bits}|Rest], Address, Env, Code, Opts) -> to_bytecode([{bits,_line, Bits}|Rest], Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env, to_bytecode(Rest, Address, Env,
@ -870,14 +870,25 @@ parse_tuple(Tokens) ->
parse_variant([{start_variant,_line} parse_variant([{start_variant,_line}
, {int,_line, Size} , {'[', _line}
, {'|',_} | Rest]) ->
, {int,_line, Tag} {Arities, Rest2} = parse_list(Rest),
, {'|',_} %% Make sure Arities is a list of bytes.
, {'(',_} Arities = [A || A <- Arities,
| Rest]) when (Size > 0), (Tag < Size) -> is_integer(A), A < 256],
{Elements , [{end_variant, _} | Rest2]} = parse_tuple(Rest),
{Size, Tag, list_to_tuple(Elements), Rest2}. [{'|',_}
, {int,_line, Tag}
, {'|',_}
, {'(',_} | Rest3] = Rest2,
{Elements , [{end_variant, _} | Rest4]} = parse_tuple(Rest3),
Size = length(Arities),
if 0 =< Tag, Tag < Size ->
Arity = lists:nth(Tag+1, Arities),
if length(Elements) =:= Arity ->
{Arities, Tag, list_to_tuple(Elements), Rest4}
end
end.
parse_value([{int,_line, Int} | Rest]) -> {Int, Rest}; parse_value([{int,_line, Int} | Rest]) -> {Int, Rest};
@ -890,8 +901,8 @@ parse_value([{'(',_line} | Rest]) ->
parse_value([{bits,_line, Bits} | Rest]) -> parse_value([{bits,_line, Bits} | Rest]) ->
{aeb_fate_data:make_bits(Bits), Rest}; {aeb_fate_data:make_bits(Bits), Rest};
parse_value([{start_variant,_line}|_] = Tokens) -> parse_value([{start_variant,_line}|_] = Tokens) ->
{Size, Tag, Values, Rest} = parse_variant(Tokens), {Arities, Tag, Values, Rest} = parse_variant(Tokens),
Variant = aeb_fate_data:make_variant(Size, Tag, Values), Variant = aeb_fate_data:make_variant(Arities, Tag, Values),
{Variant, Rest}; {Variant, Rest};
parse_value([{string,_line, String} | Rest]) -> parse_value([{string,_line, String} | Rest]) ->
{aeb_fate_data:make_string(String), Rest}; {aeb_fate_data:make_string(String), Rest};
@ -956,8 +967,7 @@ to_type([{'{', _}
, {id, _, "variant"} , {id, _, "variant"}
, {',', _} , {',', _}
, {'[', _} , {'[', _}
| Rest]) -> | Rest]) ->
%% TODO: Error handling
{ElementTypes, [{'}', _}| Rest2]} = to_list_of_types(Rest), {ElementTypes, [{'}', _}| Rest2]} = to_list_of_types(Rest),
{{variant, ElementTypes}, Rest2}. {{variant, ElementTypes}, Rest2}.

View File

@ -34,7 +34,7 @@
| name | name
| channel | channel
| bits | bits
| {variant, integer()}. | {variant, list(), integer()}.
-type fate_type() :: -type fate_type() ::
@ -120,12 +120,18 @@ make_string(S) when is_list(S) ->
?FATE_STRING(list_to_binary(lists:flatten(S))); ?FATE_STRING(list_to_binary(lists:flatten(S)));
make_string(S) when is_binary(S) -> ?FATE_STRING(S). make_string(S) when is_binary(S) -> ?FATE_STRING(S).
make_variant(Size, Tag, Values) when is_integer(Size), is_integer(Tag) make_variant(Arities, Tag, Values) ->
, 0 =< Size Arities = [A || A <- Arities, is_integer(A), A < 256],
, 0 =< Tag Size = length(Arities),
, Tag < Size if is_integer(Tag)
, is_tuple(Values) -> , 0 =< Tag
?FATE_VARIANT(Size, Tag, Values). , Tag < Size
, is_tuple(Values) ->
Arity = lists:nth(Tag+1, Arities),
if size(Values) =:= Arity ->
?FATE_VARIANT(Arities, Tag, Values)
end
end.
tuple_to_list(?FATE_TUPLE(T)) -> erlang:tuple_to_list(T). tuple_to_list(?FATE_TUPLE(T)) -> erlang:tuple_to_list(T).
@ -160,7 +166,7 @@ encode({channel, B}) when is_binary(B) -> make_channel(B);
encode({channel, I}) when is_integer(I) -> B = <<I:256>>, make_channel(B); encode({channel, I}) when is_integer(I) -> B = <<I:256>>, make_channel(B);
encode({channel, S}) when is_list(S) -> encode({channel, S}) when is_list(S) ->
make_channel(encode_address(channel, S)); make_channel(encode_address(channel, S));
encode({variant, Size, Tag, Values}) -> make_variant(Size, Tag, Values); encode({variant, Arities, Tag, Values}) -> make_variant(Arities, Tag, Values);
encode(Term) when is_integer(Term) -> make_integer(Term); encode(Term) when is_integer(Term) -> make_integer(Term);
encode(Term) when is_boolean(Term) -> make_boolean(Term); encode(Term) when is_boolean(Term) -> make_boolean(Term);
encode(Term) when is_list(Term) -> make_list([encode(E) || E <- Term]); encode(Term) when is_list(Term) -> make_list([encode(E) || E <- Term]);
@ -185,7 +191,7 @@ decode(?FATE_NAME(X)) -> {name, X};
decode(?FATE_CHANNEL(X)) -> {channel, X}; decode(?FATE_CHANNEL(X)) -> {channel, X};
decode(?FATE_BITS(Bits)) -> {bits, Bits}; decode(?FATE_BITS(Bits)) -> {bits, Bits};
decode(?FATE_TUPLE(T)) -> erlang:list_to_tuple([decode(E) || E <- T]); decode(?FATE_TUPLE(T)) -> erlang:list_to_tuple([decode(E) || E <- T]);
decode(?FATE_VARIANT(Size, Tag, Values)) -> {variant, Size, Tag, Values}; decode(?FATE_VARIANT(Arities, Tag, Values)) -> {variant, Arities, Tag, Values};
decode(S) when ?IS_FATE_STRING(S) -> binary_to_list(S); decode(S) when ?IS_FATE_STRING(S) -> binary_to_list(S);
decode(M) when ?IS_FATE_MAP(M) -> decode(M) when ?IS_FATE_MAP(M) ->
maps:from_list([{decode(K), decode(V)} || {K, V} <- maps:to_list(M)]). maps:from_list([{decode(K), decode(V)} || {K, V} <- maps:to_list(M)]).
@ -204,10 +210,12 @@ format(?FATE_BITS(B)) when B >= 0 ->
["<", format_bits(B, "") , ">"]; ["<", format_bits(B, "") , ">"];
format(?FATE_BITS(B)) when B < 0 -> format(?FATE_BITS(B)) when B < 0 ->
["!< ", format_nbits(-B-1, "") , " >"]; ["!< ", format_nbits(-B-1, "") , " >"];
format(?FATE_VARIANT(Size, Tag, T)) -> format(?FATE_VARIANT(Arities, Tag, T)) ->
["(| ", ["(| ",
lists:join("| ", [integer_to_list(Size), integer_to_list(Tag) | lists:join("| ",
[format(make_tuple(T))]]), [io_lib:format("~p", [Arities]),
integer_to_list(Tag) |
[format(make_tuple(T))]]),
" |)"]; " |)"];
format(M) when ?IS_FATE_MAP(M) -> format(M) when ?IS_FATE_MAP(M) ->
["{ ", format_kvs(maps:to_list(?FATE_MAP_VALUE(M))), " }"]; ["{ ", format_kvs(maps:to_list(?FATE_MAP_VALUE(M))), " }"];

View File

@ -28,8 +28,6 @@
%% TODO: %% TODO:
%% * Make the code production ready. %% * Make the code production ready.
%% (add tests, document exported functions). %% (add tests, document exported functions).
%% * Handle Variant types better.
%% * Handle type representations.
%% * Handle instructions. %% * Handle instructions.
%% %%
%% ------------------------------------------------------------------------ %% ------------------------------------------------------------------------
@ -62,7 +60,7 @@
-define(TYPE_BITS , 2#01010111). %% 0101 0111 - Bits typedef -define(TYPE_BITS , 2#01010111). %% 0101 0111 - Bits typedef
-define(TYPE_MAP , 2#01100111). %% 0110 0111 | Type | Type -define(TYPE_MAP , 2#01100111). %% 0110 0111 | Type | Type
-define(TYPE_STRING , 2#01110111). %% 0111 0111 - string typedef -define(TYPE_STRING , 2#01110111). %% 0111 0111 - string typedef
-define(TYPE_VARIANT , 2#10000111). %% 1000 0111 | Size | [Type] -define(TYPE_VARIANT , 2#10000111). %% 1000 0111 | [Arities] | [Type]
%% 1001 0111 %% 1001 0111
%% 1010 0111 %% 1010 0111
%% 1011 0111 %% 1011 0111
@ -82,7 +80,7 @@
-define(FALSE , 2#01111111). %% 0111 1111 -define(FALSE , 2#01111111). %% 0111 1111
%% %% 1000 1111 - FREE (Possibly for bytecode in the future.) %% %% 1000 1111 - FREE (Possibly for bytecode in the future.)
-define(OBJECT , 2#10011111). %% 1001 1111 | ObjectType | RLP encoded Array -define(OBJECT , 2#10011111). %% 1001 1111 | ObjectType | RLP encoded Array
-define(VARIANT , 2#10101111). %% 1010 1111 | encoded size | encoded tag | [encoded values] -define(VARIANT , 2#10101111). %% 1010 1111 | [encoded arities] | encoded tag | [encoded values]
-define(NIL , 2#10111111). %% 1011 1111 - Empty list -define(NIL , 2#10111111). %% 1011 1111 - Empty list
-define(NEG_BITS , 2#11001111). %% 1100 1111 | RLP encoded integer (infinite 1:s bitfield) -define(NEG_BITS , 2#11001111). %% 1100 1111 | RLP encoded integer (infinite 1:s bitfield)
-define(EMPTY_MAP , 2#11011111). %% 1101 1111 -define(EMPTY_MAP , 2#11011111). %% 1101 1111
@ -174,11 +172,24 @@ serialize(Map) when ?IS_FATE_MAP(Map) ->
<<?MAP, <<?MAP,
(rlp_integer(Size))/binary, (rlp_integer(Size))/binary,
(Elements)/binary>>; (Elements)/binary>>;
serialize(?FATE_VARIANT(Size, Tag, Values)) when 0 < Size, Size < 256, serialize(?FATE_VARIANT(Arities, Tag, Values)) ->
0 =< Tag, Tag < Size -> Arities = [A || A <- Arities, is_integer(A), A < 256],
<<?VARIANT, Size:8, Tag:8, Size = length(Arities),
(serialize(?FATE_TUPLE(Values)))/binary if is_integer(Tag)
>>. , 0 =< Tag
, Tag < Size
, is_tuple(Values) ->
Arity = lists:nth(Tag+1, Arities),
if size(Values) =:= Arity ->
EncodedArities = aeser_rlp:encode(list_to_binary(Arities)),
<<?VARIANT,
EncodedArities/binary,
Tag:8,
(serialize(?FATE_TUPLE(Values)))/binary
>>
end
end.
%% ----------------------------------------------------- %% -----------------------------------------------------
@ -363,11 +374,20 @@ deserialize2(<<?MAP, Rest/binary>>) ->
{List, Rest2} = deserialize_elements(2*Size, Rest1), {List, Rest2} = deserialize_elements(2*Size, Rest1),
Map = insert_kv(List, #{}), Map = insert_kv(List, #{}),
{?MAKE_FATE_MAP(Map), Rest2}; {?MAKE_FATE_MAP(Map), Rest2};
deserialize2(<<?VARIANT, Size:8, Tag:8, Rest/binary>>) -> deserialize2(<<?VARIANT, Rest/binary>>) ->
{AritiesBin, <<Tag:8, Rest2/binary>>} = aeser_rlp:decode_one(Rest),
Arities = binary_to_list(AritiesBin),
Size = length(Arities),
if Tag > Size -> exit({too_large_tag_in_variant, Tag, Size}); if Tag > Size -> exit({too_large_tag_in_variant, Tag, Size});
true -> true ->
{?FATE_TUPLE(T), Rest2} = deserialize2(Rest), {?FATE_TUPLE(T), Rest3} = deserialize2(Rest2),
{?FATE_VARIANT(Size, Tag, T), Rest2} Arity = lists:nth(Tag+1, Arities),
NumElements = size(T),
if NumElements =/= Arity ->
exit({tag_does_not_match_type_in_variant, Tag, Arity});
true ->
{?FATE_VARIANT(Arities, Tag, T), Rest3}
end
end. end.
insert_kv([], M) -> M; insert_kv([], M) -> M;

View File

@ -77,12 +77,13 @@ sources() ->
aeb_fate_data:make_bits(1), aeb_fate_data:make_bits(1),
aeb_fate_data:make_bits(-1), aeb_fate_data:make_bits(-1),
aeb_fate_data:make_list(make_int_list(65)), aeb_fate_data:make_list(make_int_list(65)),
aeb_fate_data:make_variant(2, 0, {FortyTwo}), aeb_fate_data:make_variant([1,2,3], 0, {FortyTwo}),
aeb_fate_data:make_variant(2, 1, {}), aeb_fate_data:make_variant([2,0], 1, {}),
aeb_fate_data:make_list([aeb_fate_data:make_variant(3, 0, {})]), aeb_fate_data:make_list([aeb_fate_data:make_variant([0,0,0], 0, {})]),
aeb_fate_data:make_variant(255, 254, {}), aeb_fate_data:make_variant([0|| _<-lists:seq(1,255)], 254, {}),
aeb_fate_data:make_variant(5, 3, {aeb_fate_data:make_boolean(true), aeb_fate_data:make_variant([0,1,2,3,4,5],
aeb_fate_data:make_list(make_int_list(3)), 3, {aeb_fate_data:make_boolean(true),
aeb_fate_data:make_string(<<"foo">>)}) aeb_fate_data:make_list(make_int_list(3)),
aeb_fate_data:make_string(<<"foo">>)})
]. ].

View File

@ -70,7 +70,7 @@ FUNCTION foo () : {tuple, []}
AND var255 0x294a24f6 var189 AND var255 0x294a24f6 var189
OR (| 2 | 0 | ( (), (42) ) |) arg168 var107 OR (| [2,0] | 0 | ( (), (42) ) |) arg168 var107
NOT arg124 a NOT arg124 a
@ -136,7 +136,7 @@ FUNCTION foo () : {tuple, []}
BITS_CLEAR arg98 a arg164 BITS_CLEAR arg98 a arg164
BITS_TEST a a242 (| 5 | 2 | (1, "foo", ()) |) BITS_TEST a a242 (| [0,0,3] | 2 | (1, "foo", ()) |)
BITS_SUM a244 a71 BITS_SUM a244 a71
@ -176,7 +176,7 @@ FUNCTION foo () : {tuple, []}
LOG1 arg94 arg86 arg208 LOG1 arg94 arg86 arg208
LOG2 a113 (| 5 | 2 | (1, "foo", ()) |) arg238 var108 LOG2 a113 (| [0,1,3] | 2 | (1, "foo", ()) |) arg238 var108
LOG3 arg255 arg15 arg211 var139 arg44 LOG3 arg255 arg15 arg211 var139 arg44
@ -186,7 +186,7 @@ FUNCTION foo () : {tuple, []}
SPEND @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv var136 SPEND @ak_nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv var136
ORACLE_REGISTER arg29 48 ((| 5 | 2 | (1, "foo", ()) |)) arg65 { <> => false} <> ORACLE_REGISTER arg29 48 ((| [0,1,3] | 2 | (1, "foo", ()) |)) arg65 { <> => false} <>
ORACLE_QUERY ORACLE_QUERY
@ -220,7 +220,7 @@ FUNCTION foo () : {tuple, []}
BLAKE2B BLAKE2B
DUMMY7ARG a a 7607708484837907159893701471377343595877 (| 2 | 0 | ( [], [ 45, { 1 => 3441201581501946066216994494994943246334} ] ) |) a0 var56 "foo" DUMMY7ARG a a 7607708484837907159893701471377343595877 (| [2,1] | 0 | ( [], [ 45, { 1 => 3441201581501946066216994494994943246334} ] ) |) a0 var56 "foo"
DUMMY8ARG 3673679924816289365509492271980889822579 a69 arg242 var237 a175 arg106 () var255 DUMMY8ARG 3673679924816289365509492271980889822579 a69 arg242 var237 a175 arg106 () var255

View File

@ -70,8 +70,8 @@ FUNCTION address() : address
;; Option(integer) = NONE | SOME(integer) ;; Option(integer) = NONE | SOME(integer)
FUNCTION variant_none() : {variant, [{tuple, []}, {tuple, [integer]}]} FUNCTION variant_none() : {variant, [{tuple, []}, {tuple, [integer]}]}
RETURNR (| 2 | 0 | () |) RETURNR (| [0,1] | 0 | () |)
;; Option(integer) = NONE | SOME(integer) ;; Option(integer) = NONE | SOME(integer)
FUNCTION variant_some() : {variant, [{tuple, []}, {tuple, [integer]}]} FUNCTION variant_some() : {variant, [{tuple, []}, {tuple, [integer]}]}
RETURNR (| 2 | 1 | (42) |) RETURNR (| [0,1] | 1 | (42) |)