Add hash, signature and object types.
This commit is contained in:
parent
34ae94e3e7
commit
c614da15e0
@ -1,23 +1,35 @@
|
||||
-define(FATE_INTEGER_T, integer()).
|
||||
-define(FATE_BYTE_T, 0..255).
|
||||
-define(FATE_BOOLEAN_T, true | false).
|
||||
-define(FATE_NIL_T, []).
|
||||
-define(FATE_LIST_T, list()).
|
||||
-define(FATE_UNIT_T, {tuple, {}}).
|
||||
-define(FATE_MAP_T, #{ fate_type() => fate_type() }).
|
||||
-define(FATE_STRING_T, binary()).
|
||||
-define(FATE_ADDRESS_T, {address, <<_:256>>}).
|
||||
-define(FATE_VARIANT_T, {variant, ?FATE_BYTE_T, ?FATE_BYTE_T, tuple()}).
|
||||
-define(FATE_VOID_T, void).
|
||||
-define(FATE_TUPLE_T, {tuple, tuple()}).
|
||||
-define(FATE_BITS_T, {bits, integer()}).
|
||||
-define(FATE_INTEGER_T, integer()).
|
||||
-define(FATE_BYTE_T, 0..255).
|
||||
-define(FATE_BOOLEAN_T, true | false).
|
||||
-define(FATE_NIL_T, []).
|
||||
-define(FATE_LIST_T, list()).
|
||||
-define(FATE_UNIT_T, {tuple, {}}).
|
||||
-define(FATE_MAP_T, #{ fate_type() => fate_type() }).
|
||||
-define(FATE_STRING_T, binary()).
|
||||
-define(FATE_ADDRESS_T, {address, <<_:256>>}).
|
||||
-define(FATE_HASH_T, {hash, binary()}).
|
||||
-define(FATE_SIGNATURE_T, {signature, binary()}).
|
||||
-define(FATE_CONTRACT_T, {contract, <<_:256>>}).
|
||||
-define(FATE_ORACLE_T, {oracle, <<_:256>>}).
|
||||
-define(FATE_NAME_T, {name, <<_:256>>}).
|
||||
-define(FATE_CHANNEL_T, {channel, <<_:256>>}).
|
||||
-define(FATE_VARIANT_T, {variant, ?FATE_BYTE_T, ?FATE_BYTE_T, tuple()}).
|
||||
-define(FATE_VOID_T, void).
|
||||
-define(FATE_TUPLE_T, {tuple, tuple()}).
|
||||
-define(FATE_BITS_T, {bits, integer()}).
|
||||
|
||||
-define(IS_FATE_INTEGER(X), is_integer(X)).
|
||||
-define(IS_FATE_LIST(X), (is_list(X))).
|
||||
-define(IS_FATE_STRING(X), (is_binary(X))).
|
||||
-define(IS_FATE_MAP(X), (is_map(X))).
|
||||
-define(IS_FATE_TUPLE(X), (is_tuple(X) andalso (tuple == element(1, X) andalso is_tuple(element(2, X))))).
|
||||
-define(IS_FATE_INTEGER(X), (is_integer(X))).
|
||||
-define(IS_FATE_LIST(X), (is_list(X))).
|
||||
-define(IS_FATE_STRING(X), (is_binary(X))).
|
||||
-define(IS_FATE_MAP(X), (is_map(X))).
|
||||
-define(IS_FATE_TUPLE(X), (is_tuple(X) andalso (tuple == element(1, X) andalso is_tuple(element(2, X))))).
|
||||
-define(IS_FATE_ADDRESS(X), (is_tuple(X) andalso (address == element(1, X) andalso is_binary(element(2, X))))).
|
||||
-define(IS_FATE_HASH(X), (is_tuple(X) andalso (hash == element(1, X) andalso is_binary(element(2, X))))).
|
||||
-define(IS_FATE_SIGNATURE(X), (is_tuple(X) andalso (signature == element(1, X) andalso is_binary(element(2, X))))).
|
||||
-define(IS_FATE_CONTRACT(X), (is_tuple(X) andalso (contract == element(1, X) andalso is_binary(element(2, X))))).
|
||||
-define(IS_FATE_ORACLE(X), (is_tuple(X) andalso (oracle == element(1, X) andalso is_binary(element(2, X))))).
|
||||
-define(IS_FATE_NAME(X), (is_tuple(X) andalso (name == element(1, X) andalso is_binary(element(2, X))))).
|
||||
-define(IS_FATE_CHANNEL(X), (is_tuple(X) andalso (channel == element(1, X) andalso is_binary(element(2, X))))).
|
||||
-define(IS_FATE_BITS(X), (is_tuple(X) andalso (bits == element(1, X) andalso is_integer(element(2, X))))).
|
||||
-define(IS_FATE_VARIANT(X), (is_tuple(X)
|
||||
andalso
|
||||
@ -28,16 +40,28 @@
|
||||
))).
|
||||
-define(IS_FATE_BOOLEAN(X), is_boolean(X)).
|
||||
|
||||
-define(FATE_UNIT, {tuple, {}}).
|
||||
-define(FATE_TUPLE(T), {tuple, T}).
|
||||
-define(FATE_ADDRESS(A), {address, A}).
|
||||
-define(FATE_BITS(B), {bits, B}).
|
||||
-define(FATE_UNIT, {tuple, {}}).
|
||||
-define(FATE_TUPLE(T), {tuple, T}).
|
||||
-define(FATE_ADDRESS(A), {address, A}).
|
||||
-define(FATE_HASH(X), {hash, X}).
|
||||
-define(FATE_SIGNATURE(S), {signature, S}).
|
||||
-define(FATE_CONTRACT(X), {contract, X}).
|
||||
-define(FATE_ORACLE(X), {oracle, X}).
|
||||
-define(FATE_NAME(X), {name, X}).
|
||||
-define(FATE_CHANNEL(X), {channel, X}).
|
||||
-define(FATE_BITS(B), {bits, B}).
|
||||
|
||||
|
||||
-define(FATE_INTEGER_VALUE(X), (X)).
|
||||
-define(FATE_LIST_VALUE(X), (X)).
|
||||
-define(FATE_STRING_VALUE(X), (X)).
|
||||
-define(FATE_ADDRESS_VALUE(X), (element(2, X))).
|
||||
-define(FATE_HASH_VALUE(X), (element(2, X))).
|
||||
-define(FATE_SIGNATURE_VALUE(X), (element(2, X))).
|
||||
-define(FATE_CONTRACT_VALUE(X), (element(2, X))).
|
||||
-define(FATE_ORACLE_VALUE(X), (element(2, X))).
|
||||
-define(FATE_NAME_VALUE(X), (element(2, X))).
|
||||
-define(FATE_CHANNEL_VALUE(X), (element(2, X))).
|
||||
-define(FATE_MAP_VALUE(X), (X)).
|
||||
-define(FATE_MAP_SIZE(X), (map_size(X))).
|
||||
-define(FATE_STRING_SIZE(X), (byte_size(X))).
|
||||
|
@ -40,9 +40,12 @@
|
||||
%%% -2374683271468723648732648736498712634876147
|
||||
%%% 1b. Integers as Hexadecimals:: 0x{Hexdigits}
|
||||
%%% 0x0deadbeef0
|
||||
%%% 2. addresses, a base58 encoded string starting with #{base58char}
|
||||
%%% followed by up to 64 hex chars
|
||||
%%% #00000deadbeef
|
||||
%%% 2a. addresses, a base58 encoded string prefixed with @
|
||||
%%% @foo
|
||||
%%% 2b. contract addresse: ct_{base58char}+
|
||||
%%% 2c. oracle addresse: ok_{base58char}+
|
||||
%%% 2d. name addresse: nm_{base58char}+
|
||||
%%% 2e. channel addresse: ch_{base58char}+
|
||||
%%% 3. Boolean true or false
|
||||
%%% true
|
||||
%%% false
|
||||
@ -708,49 +711,16 @@ serialize_data(_, Data) ->
|
||||
aeb_fate_encoding:serialize(Data).
|
||||
|
||||
serialize_signature({Args, RetType}) ->
|
||||
[serialize_type({tuple, Args}) |
|
||||
serialize_type(RetType)].
|
||||
[aeb_fate_encoding:serialize_type({tuple, Args}) |
|
||||
aeb_fate_encoding:serialize_type(RetType)].
|
||||
|
||||
|
||||
|
||||
deserialize_signature(Binary) ->
|
||||
{{tuple, Args}, Rest} = deserialize_type(Binary),
|
||||
{RetType, Rest2} = deserialize_type(Rest),
|
||||
{{tuple, Args}, Rest} = aeb_fate_encoding:deserialize_type(Binary),
|
||||
{RetType, Rest2} = aeb_fate_encoding:deserialize_type(Rest),
|
||||
{{Args, RetType}, Rest2}.
|
||||
|
||||
deserialize_type(<<0, Rest/binary>>) -> {integer, Rest};
|
||||
deserialize_type(<<1, Rest/binary>>) -> {boolean, Rest};
|
||||
deserialize_type(<<2, Rest/binary>>) ->
|
||||
{T, Rest2} = deserialize_type(Rest),
|
||||
{{list, T}, Rest2};
|
||||
deserialize_type(<<3, N, Rest/binary>>) ->
|
||||
{Ts, Rest2} = deserialize_types(N, Rest, []),
|
||||
{{tuple, Ts}, Rest2};
|
||||
deserialize_type(<<4, Rest/binary>>) -> {address, Rest};
|
||||
deserialize_type(<<5, Rest/binary>>) -> {bits, Rest};
|
||||
deserialize_type(<<6, Rest/binary>>) ->
|
||||
{K, Rest2} = deserialize_type(Rest),
|
||||
{V, Rest3} = deserialize_type(Rest2),
|
||||
{{map, K, V}, Rest3};
|
||||
deserialize_type(<<7, Rest/binary>>) ->
|
||||
{string, Rest};
|
||||
deserialize_type(<<8, Size, Rest/binary>>) ->
|
||||
{Variants, Rest2} = deserialize_variants(Size, Rest, []),
|
||||
{{variant, Variants}, Rest2}.
|
||||
|
||||
deserialize_variants(0, Rest, Variants) ->
|
||||
{lists:reverse(Variants), Rest};
|
||||
deserialize_variants(N, Rest, Variants) ->
|
||||
{T, Rest2} = deserialize_type(Rest),
|
||||
deserialize_variants(N-1, Rest2, [T|Variants]).
|
||||
|
||||
|
||||
|
||||
deserialize_types(0, Binary, Acc) ->
|
||||
{lists:reverse(Acc), Binary};
|
||||
deserialize_types(N, Binary, Acc) ->
|
||||
{T, Rest} = deserialize_type(Binary),
|
||||
deserialize_types(N-1, Rest, [T | Acc]).
|
||||
|
||||
|
||||
to_hexstring(ByteList) ->
|
||||
@ -786,10 +756,41 @@ to_bytecode([{string,_line, String}|Rest], Address, Env, Code, Opts) ->
|
||||
to_bytecode(Rest, Address, Env,
|
||||
[{immediate, aeb_fate_data:make_string(String)}|Code],
|
||||
Opts);
|
||||
to_bytecode([{address,_line, Value}|Rest], Address, Env, Code, Opts) ->
|
||||
to_bytecode([{address,_line, {address, Value}}|Rest],
|
||||
Address, Env, Code, Opts) ->
|
||||
to_bytecode(Rest, Address, Env,
|
||||
[{immediate, aeb_fate_data:make_address(Value)}|Code],
|
||||
Opts);
|
||||
to_bytecode([{address,_line, {contract, Value}}|Rest],
|
||||
Address, Env, Code, Opts) ->
|
||||
to_bytecode(Rest, Address, Env,
|
||||
[{immediate, aeb_fate_data:make_contract(Value)}|Code],
|
||||
Opts);
|
||||
to_bytecode([{address,_line, {oracle, Value}}|Rest],
|
||||
Address, Env, Code, Opts) ->
|
||||
to_bytecode(Rest, Address, Env,
|
||||
[{immediate, aeb_fate_data:make_oracle(Value)}|Code],
|
||||
Opts);
|
||||
to_bytecode([{address,_line, {name, Value}}|Rest],
|
||||
Address, Env, Code, Opts) ->
|
||||
to_bytecode(Rest, Address, Env,
|
||||
[{immediate, aeb_fate_data:make_name(Value)}|Code],
|
||||
Opts);
|
||||
to_bytecode([{address,_line, {channel, Value}}|Rest],
|
||||
Address, Env, Code, Opts) ->
|
||||
to_bytecode(Rest, Address, Env,
|
||||
[{immediate, aeb_fate_data:make_contract(Value)}|Code],
|
||||
Opts);
|
||||
to_bytecode([{hash,_line, Value}|Rest],
|
||||
Address, Env, Code, Opts) ->
|
||||
to_bytecode(Rest, Address, Env,
|
||||
[{immediate, aeb_fate_data:make_hash(Value)}|Code],
|
||||
Opts);
|
||||
to_bytecode([{signature,_line, Value}|Rest],
|
||||
Address, Env, Code, Opts) ->
|
||||
to_bytecode(Rest, Address, Env,
|
||||
[{immediate, aeb_fate_data:make_signature(Value)}|Code],
|
||||
Opts);
|
||||
to_bytecode([{id,_line, ID}|Rest], Address, Env, Code, Opts) ->
|
||||
{Hash, Env2} = insert_symbol(ID, Env),
|
||||
to_bytecode(Rest, Address, Env2, [{immediate, Hash}|Code], Opts);
|
||||
@ -878,7 +879,6 @@ parse_variant([{start_variant,_line}
|
||||
|
||||
parse_value([{int,_line, Int} | Rest]) -> {Int, Rest};
|
||||
parse_value([{boolean,_line, Bool} | Rest]) -> {Bool, Rest};
|
||||
parse_value([{hash,_line, Hash} | Rest]) -> {Hash, Rest};
|
||||
parse_value([{'{',_line} | Rest]) -> parse_map(Rest);
|
||||
parse_value([{'[',_line} | Rest]) -> parse_list(Rest);
|
||||
parse_value([{'(',_line} | Rest]) ->
|
||||
@ -892,8 +892,20 @@ parse_value([{start_variant,_line}|_] = Tokens) ->
|
||||
{Variant, Rest};
|
||||
parse_value([{string,_line, String} | Rest]) ->
|
||||
{aeb_fate_data:make_string(String), Rest};
|
||||
parse_value([{address,_line, Address} | Rest]) ->
|
||||
{aeb_fate_data:make_address(Address), Rest}.
|
||||
parse_value([{address,_line, {address, Address}} | Rest]) ->
|
||||
{aeb_fate_data:make_address(Address), Rest};
|
||||
parse_value([{address,_line, {contract, Address}} | Rest]) ->
|
||||
{aeb_fate_data:make_contract(Address), Rest};
|
||||
parse_value([{address,_line, {oracle, Address}} | Rest]) ->
|
||||
{aeb_fate_data:make_oracle(Address), Rest};
|
||||
parse_value([{address,_line, {name, Address}} | Rest]) ->
|
||||
{aeb_fate_data:make_name(Address), Rest};
|
||||
parse_value([{address,_line, {channel, Address}} | Rest]) ->
|
||||
{aeb_fate_data:make_channel(Address), Rest};
|
||||
parse_value([{hash,_line, Hash} | Rest]) ->
|
||||
{aeb_fate_data:make_hash(Hash), Rest};
|
||||
parse_value([{signature,_line, Hash} | Rest]) ->
|
||||
{aeb_fate_data:make_signature(Hash), Rest}.
|
||||
|
||||
to_fun_def([{id, _, Name}, {'(', _} | Rest]) ->
|
||||
{ArgsType, [{'to', _} | Rest2]} = to_arg_types(Rest),
|
||||
@ -913,11 +925,17 @@ to_arg_types(Tokens) ->
|
||||
|
||||
%% Type handling
|
||||
|
||||
to_type([{id, _, "integer"} | Rest]) -> {integer, Rest};
|
||||
to_type([{id, _, "boolean"} | Rest]) -> {boolean, Rest};
|
||||
to_type([{id, _, "string"} | Rest]) -> {string, Rest};
|
||||
to_type([{id, _, "address"} | Rest]) -> {address, Rest};
|
||||
to_type([{id, _, "bits"} | Rest]) -> {bits, Rest};
|
||||
to_type([{id, _, "integer"} | Rest]) -> {integer, Rest};
|
||||
to_type([{id, _, "boolean"} | Rest]) -> {boolean, Rest};
|
||||
to_type([{id, _, "string"} | Rest]) -> {string, Rest};
|
||||
to_type([{id, _, "address"} | Rest]) -> {address, Rest};
|
||||
to_type([{id, _, "contract"} | Rest]) -> {contract, Rest};
|
||||
to_type([{id, _, "oracle"} | Rest]) -> {oracle, Rest};
|
||||
to_type([{id, _, "name"} | Rest]) -> {name, Rest};
|
||||
to_type([{id, _, "channel"} | Rest]) -> {channel, Rest};
|
||||
to_type([{id, _, "hash"} | Rest]) -> {hash, Rest};
|
||||
to_type([{id, _, "signature"} | Rest]) -> {signature, Rest};
|
||||
to_type([{id, _, "bits"} | Rest]) -> {bits, Rest};
|
||||
to_type([{'{', _}, {id, _, "list"}, {',', _} | Rest]) ->
|
||||
%% TODO: Error handling
|
||||
{ListType, [{'}', _}| Rest2]} = to_type(Rest),
|
||||
@ -951,25 +969,6 @@ to_list_of_types(Tokens) ->
|
||||
{[Type], Rest}
|
||||
end.
|
||||
|
||||
-spec serialize_type(aeb_fate_data:fate_type_type()) -> [byte()].
|
||||
serialize_type(integer) -> [0];
|
||||
serialize_type(boolean) -> [1];
|
||||
serialize_type({list, T}) -> [2 | serialize_type(T)];
|
||||
serialize_type({tuple, Ts}) ->
|
||||
case length(Ts) of
|
||||
N when N =< 255 ->
|
||||
[3, N | [serialize_type(T) || T <- Ts]]
|
||||
end;
|
||||
serialize_type(address) -> [4];
|
||||
serialize_type(bits) -> [5];
|
||||
serialize_type({map, K, V}) -> [6 | serialize_type(K) ++ serialize_type(V)];
|
||||
serialize_type(string) -> [7];
|
||||
serialize_type({variant, ListOfVariants}) ->
|
||||
Size = length(ListOfVariants),
|
||||
if Size < 256 ->
|
||||
[8, Size | [serialize_type(T) || T <- ListOfVariants]]
|
||||
end.
|
||||
|
||||
|
||||
%% -------------------------------------------------------------------
|
||||
%% Helper functions
|
||||
|
@ -4,7 +4,7 @@
|
||||
%%% @doc
|
||||
%%% Handling FATE code.
|
||||
%%% @end
|
||||
###REPLACEWITHNOTE###
|
||||
%%% ###REPLACEWITHNOTE###
|
||||
%%%-------------------------------------------------------------------
|
||||
|
||||
Definitions.
|
||||
@ -13,9 +13,13 @@ HEXDIGIT = [0-9a-fA-F]
|
||||
LOWER = [a-z_]
|
||||
UPPER = [A-Z]
|
||||
BASE58 = [123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]
|
||||
BASE64 = [ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxy0123456789+/=]
|
||||
INT = {DIGIT}+
|
||||
HEX = 0x{HEXDIGIT}+
|
||||
HASH = #{BASE58}+
|
||||
OBJECT = [a-z][a-z]_{BASE58}+
|
||||
ADDRESS = @{BASE58}+
|
||||
HASH = #{BASE64}+
|
||||
SIG = \${BASE64}+
|
||||
WS = [\000-\s]
|
||||
ID = {LOWER}[a-zA-Z0-9_]*
|
||||
STRING = "[^"]*"
|
||||
@ -30,7 +34,7 @@ a{INT} : {token, {stack, TokenLine, parse_acc(TokenChars)}}.
|
||||
true : {token, {boolean, TokenLine, true}}.
|
||||
false : {token, {boolean, TokenLine, false}}.
|
||||
|
||||
###REPLACEWITHOPTOKENS###
|
||||
%% ###REPLACEWITHOPTOKENS###
|
||||
|
||||
FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}.
|
||||
|
||||
@ -43,7 +47,13 @@ FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}.
|
||||
-{INT} :
|
||||
{token, {int, TokenLine, parse_int(TokenChars)}}.
|
||||
{HASH} :
|
||||
{token, {address, TokenLine, parse_hash(TokenChars)}}.
|
||||
{token, {hash, TokenLine, parse_hash(TokenChars)}}.
|
||||
{SIG} :
|
||||
{token, {signature, TokenLine, parse_signature(TokenChars)}}.
|
||||
{ADDRESS} :
|
||||
{token, {address, TokenLine, {address, parse_address(TokenChars)}}}.
|
||||
{OBJECT} :
|
||||
{token, {object, TokenLine, parse_object(TokenChars)}}.
|
||||
{STRING} :
|
||||
{token, {string, TokenLine, list_to_binary(TokenChars)}}.
|
||||
{BITS} :
|
||||
@ -102,8 +112,26 @@ parse_acc("a" ++ N) -> list_to_integer(N).
|
||||
|
||||
|
||||
parse_hash("#" ++ Chars) ->
|
||||
base64:decode(Chars).
|
||||
|
||||
parse_signature("$" ++ Chars) ->
|
||||
base64:decode(Chars).
|
||||
|
||||
parse_address("@" ++ Chars) ->
|
||||
base58_to_address(Chars).
|
||||
|
||||
parse_object("ct_" ++ Chars) ->
|
||||
{contract, base58_to_address(Chars)};
|
||||
parse_object("ok_" ++ Chars) ->
|
||||
{oracle, base58_to_address(Chars)};
|
||||
parse_object("nm_" ++ Chars) ->
|
||||
{name, base58_to_address(Chars)};
|
||||
parse_object("ch_" ++ Chars) ->
|
||||
{channel, base58_to_address(Chars)};
|
||||
parse_object("ak_" ++ Chars) ->
|
||||
{address, base58_to_address(Chars)}.
|
||||
|
||||
|
||||
scan(S) ->
|
||||
string(S).
|
||||
|
||||
@ -139,4 +167,4 @@ base58_to_integer([Char | Str]) ->
|
||||
base58_to_address(Base58) ->
|
||||
I = base58_to_integer(Base58),
|
||||
Bin = <<I:256>>,
|
||||
Bin.
|
||||
Bin.
|
||||
|
@ -4,18 +4,22 @@
|
||||
|
||||
-module(aeb_fate_data).
|
||||
|
||||
-type fate_integer() :: ?FATE_INTEGER_T.
|
||||
-type fate_boolean() :: ?FATE_BOOLEAN_T.
|
||||
-type fate_nil() :: ?FATE_NIL_T.
|
||||
-type fate_list() :: ?FATE_LIST_T.
|
||||
-type fate_unit() :: ?FATE_UNIT_T.
|
||||
-type fate_map() :: ?FATE_MAP_T.
|
||||
-type fate_string() :: ?FATE_STRING_T.
|
||||
-type fate_address() :: ?FATE_ADDRESS_T.
|
||||
|
||||
-type fate_variant() :: ?FATE_VARIANT_T.
|
||||
|
||||
-type fate_tuple() :: ?FATE_TUPLE_T.
|
||||
-type fate_integer() :: ?FATE_INTEGER_T.
|
||||
-type fate_boolean() :: ?FATE_BOOLEAN_T.
|
||||
-type fate_nil() :: ?FATE_NIL_T.
|
||||
-type fate_list() :: ?FATE_LIST_T.
|
||||
-type fate_unit() :: ?FATE_UNIT_T.
|
||||
-type fate_map() :: ?FATE_MAP_T.
|
||||
-type fate_string() :: ?FATE_STRING_T.
|
||||
-type fate_address() :: ?FATE_ADDRESS_T.
|
||||
-type fate_hash() :: ?FATE_HASH_T.
|
||||
-type fate_contract() :: ?FATE_CONTRACT_T.
|
||||
-type fate_oracle() :: ?FATE_ORACLE_T.
|
||||
-type fate_name() :: ?FATE_NAME_T.
|
||||
-type fate_channel() :: ?FATE_CHANNEL_T.
|
||||
-type fate_signature() :: ?FATE_SIGNATURE_T.
|
||||
-type fate_variant() :: ?FATE_VARIANT_T.
|
||||
-type fate_tuple() :: ?FATE_TUPLE_T.
|
||||
|
||||
-type fate_type_type() :: integer
|
||||
| boolean
|
||||
@ -23,6 +27,12 @@
|
||||
| {map, fate_type(), fate_type()}
|
||||
| {tuple, [fate_type()]}
|
||||
| address
|
||||
| hash
|
||||
| signature
|
||||
| contract
|
||||
| oracle
|
||||
| name
|
||||
| channel
|
||||
| bits
|
||||
| {variant, integer()}.
|
||||
|
||||
@ -36,6 +46,12 @@
|
||||
| fate_tuple()
|
||||
| fate_string()
|
||||
| fate_address()
|
||||
| fate_hash()
|
||||
| fate_signature()
|
||||
| fate_contract()
|
||||
| fate_oracle()
|
||||
| fate_name()
|
||||
| fate_channel()
|
||||
| fate_variant()
|
||||
| fate_map()
|
||||
| fate_type_type().
|
||||
@ -49,6 +65,12 @@
|
||||
, fate_tuple/0
|
||||
, fate_string/0
|
||||
, fate_address/0
|
||||
, fate_hash/0
|
||||
, fate_signature/0
|
||||
, fate_contract/0
|
||||
, fate_oracle/0
|
||||
, fate_name/0
|
||||
, fate_channel/0
|
||||
, fate_variant/0
|
||||
, fate_map/0
|
||||
, fate_type_type/0
|
||||
@ -62,6 +84,12 @@
|
||||
, make_string/1
|
||||
, make_map/1
|
||||
, make_address/1
|
||||
, make_hash/1
|
||||
, make_signature/1
|
||||
, make_contract/1
|
||||
, make_oracle/1
|
||||
, make_name/1
|
||||
, make_channel/1
|
||||
, make_bits/1
|
||||
, make_unit/0
|
||||
, tuple_to_list/1
|
||||
@ -71,19 +99,26 @@
|
||||
-export([format/1]).
|
||||
|
||||
|
||||
make_integer(I) when is_integer(I) -> ?MAKE_FATE_INTEGER(I).
|
||||
|
||||
make_boolean(true) -> ?FATE_TRUE;
|
||||
make_boolean(false) -> ?FATE_FALSE.
|
||||
make_list([]) -> ?FATE_NIL;
|
||||
make_list(L) -> ?MAKE_FATE_LIST(L).
|
||||
make_string(S) when is_list(S) ->
|
||||
make_list([]) -> ?FATE_NIL;
|
||||
make_list(L) -> ?MAKE_FATE_LIST(L).
|
||||
make_unit() -> ?FATE_UNIT.
|
||||
make_tuple(T) -> ?FATE_TUPLE(T).
|
||||
make_map(M) -> ?MAKE_FATE_MAP(M).
|
||||
make_address(X) -> ?FATE_ADDRESS(X).
|
||||
make_hash(X) -> ?FATE_HASH(X).
|
||||
make_signature(X) -> ?FATE_SIGNATURE(X).
|
||||
make_contract(X) -> ?FATE_CONTRACT(X).
|
||||
make_oracle(X) -> ?FATE_ORACLE(X).
|
||||
make_name(X) -> ?FATE_NAME(X).
|
||||
make_channel(X) -> ?FATE_CHANNEL(X).
|
||||
make_integer(I) when is_integer(I) -> ?MAKE_FATE_INTEGER(I).
|
||||
make_bits(I) when is_integer(I) -> ?FATE_BITS(I).
|
||||
make_string(S) when is_list(S) ->
|
||||
?FATE_STRING(list_to_binary(lists:flatten(S)));
|
||||
make_string(S) when is_binary(S) -> ?FATE_STRING(S).
|
||||
make_unit() -> ?FATE_UNIT.
|
||||
make_tuple(T) -> ?FATE_TUPLE(T).
|
||||
make_map(M) -> ?MAKE_FATE_MAP(M).
|
||||
make_address(A) -> ?FATE_ADDRESS(A).
|
||||
make_bits(I) when is_integer(I) -> ?FATE_BITS(I).
|
||||
make_string(S) when is_binary(S) -> ?FATE_STRING(S).
|
||||
|
||||
make_variant(Size, Tag, Values) when is_integer(Size), is_integer(Tag)
|
||||
, 0 =< Size
|
||||
@ -103,6 +138,22 @@ encode({bits, Term}) when is_integer(Term) -> make_bits(Term);
|
||||
encode({address, B}) when is_binary(B) -> make_address(B);
|
||||
encode({address, I}) when is_integer(I) -> B = <<I:256>>, make_address(B);
|
||||
encode({address, S}) when is_list(S) -> make_address(base58_to_address(S));
|
||||
encode({hash, H}) when is_binary(H) -> make_hash(H);
|
||||
encode({hash, H}) when is_list(H) -> make_hash(base64:decode(H));
|
||||
encode({signature, S}) when is_binary(S) -> make_signature(S);
|
||||
encode({signature, S}) when is_list(S) -> make_signature(base64:decode(S));
|
||||
encode({contract, B}) when is_binary(B) -> make_contract(B);
|
||||
encode({contract, I}) when is_integer(I) -> B = <<I:256>>, make_contract(B);
|
||||
encode({contract, S}) when is_list(S) -> make_contract(base58_to_address(S));
|
||||
encode({oracle, B}) when is_binary(B) -> make_oracle(B);
|
||||
encode({oracle, I}) when is_integer(I) -> B = <<I:256>>, make_oracle(B);
|
||||
encode({oracle, S}) when is_list(S) -> make_oracle(base58_to_address(S));
|
||||
encode({name, B}) when is_binary(B) -> make_name(B);
|
||||
encode({name, I}) when is_integer(I) -> B = <<I:256>>, make_name(B);
|
||||
encode({name, S}) when is_list(S) -> make_name(base58_to_address(S));
|
||||
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, S}) when is_list(S) -> make_channel(base58_to_address(S));
|
||||
encode({variant, Size, Tag, Values}) -> make_variant(Size, Tag, Values);
|
||||
encode(Term) when is_integer(Term) -> make_integer(Term);
|
||||
encode(Term) when is_boolean(Term) -> make_boolean(Term);
|
||||
@ -120,8 +171,14 @@ decode(?FATE_TRUE) -> true;
|
||||
decode(?FATE_FALSE) -> false;
|
||||
decode(L) when ?IS_FATE_LIST(L) -> [decode(E) || E <- L];
|
||||
decode(?FATE_ADDRESS(<<Address:256>>)) -> {address, Address};
|
||||
decode(?FATE_BITS(Bits)) -> {bits, Bits};
|
||||
decode(?FATE_TUPLE(T)) -> erlang:list_to_tuple([decode(E) || E <- T]);
|
||||
decode(?FATE_HASH(H)) -> {hash, H};
|
||||
decode(?FATE_SIGNATURE(S)) -> {signature, S};
|
||||
decode(?FATE_CONTRACT(X)) -> {contract, X};
|
||||
decode(?FATE_ORACLE(X)) -> {oracle, X};
|
||||
decode(?FATE_NAME(X)) -> {name, X};
|
||||
decode(?FATE_CHANNEL(X)) -> {channel, X};
|
||||
decode(?FATE_BITS(Bits)) -> {bits, Bits};
|
||||
decode(?FATE_TUPLE(T)) -> erlang:list_to_tuple([decode(E) || E <- T]);
|
||||
decode(?FATE_VARIANT(Size, Tag, Values)) -> {variant, Size, Tag, Values};
|
||||
decode(S) when ?IS_FATE_STRING(S) -> binary_to_list(S);
|
||||
decode(M) when ?IS_FATE_MAP(M) ->
|
||||
@ -148,7 +205,13 @@ format(?FATE_VARIANT(Size, Tag, T)) ->
|
||||
" |)"];
|
||||
format(M) when ?IS_FATE_MAP(M) ->
|
||||
["{ ", format_kvs(maps:to_list(?FATE_MAP_VALUE(M))), " }"];
|
||||
format(?FATE_ADDRESS(Address)) -> ["#", address_to_base58(Address)];
|
||||
format(?FATE_ADDRESS(Address)) -> [address_to_base58(Address)];
|
||||
format(?FATE_HASH(X)) -> ["#", base64:encode(X)];
|
||||
format(?FATE_SIGNATURE(X)) -> ["$", base64:encode(X)];
|
||||
format(?FATE_CONTRACT(X)) -> ["ct_", address_to_base58(X)];
|
||||
format(?FATE_ORACLE(X)) -> ["ok_", address_to_base58(X)];
|
||||
format(?FATE_NAME(X)) -> ["nm_", address_to_base58(X)];
|
||||
format(?FATE_CHANNEL(X)) -> ["ch_", address_to_base58(X)];
|
||||
format(V) -> exit({not_a_fate_type, V}).
|
||||
|
||||
format_bits(0, Acc) -> Acc;
|
||||
|
@ -37,7 +37,9 @@
|
||||
|
||||
-export([ deserialize/1
|
||||
, deserialize_one/1
|
||||
, deserialize_type/1
|
||||
, serialize/1
|
||||
, serialize_type/1
|
||||
]).
|
||||
|
||||
-include("aeb_fate_data.hrl").
|
||||
@ -47,38 +49,62 @@
|
||||
|
||||
-define(SMALL_INT , 2#0). %% sxxxxxx 0 - 6 bit integer with sign bit
|
||||
%% 1 Set below
|
||||
-define(LONG_STRING , 2#00000001). %% 000000 01 - RLP encoded array, size >= 64
|
||||
-define(SHORT_STRING , 2#01). %% xxxxxx 01 - [bytes], 0 < xxxxxx:size < 64
|
||||
-define(LONG_STRING , 2#00000001). %% 000000 01 | RLP encoded array - when size >= 64
|
||||
-define(SHORT_STRING , 2#01). %% xxxxxx 01 | [bytes] - when 0 < xxxxxx:size < 64
|
||||
%% 11 Set below
|
||||
-define(SHORT_LIST , 2#0011). %% xxxx 0011 - [encoded elements], 0 < length < 16
|
||||
%% xxxx 0111 - FREE (For typedefs in future)
|
||||
-define(LONG_TUPLE , 2#00001011). %% 0000 1011 - RLP encoded (size - 16) + [encoded elements],
|
||||
-define(SHORT_TUPLE , 2#1011). %% xxxx 1011 - [encoded elements], 0 < size < 16
|
||||
-define(SHORT_LIST , 2#0011). %% xxxx 0011 | [encoded elements] when 0 < length < 16
|
||||
%% xxxx 0111
|
||||
-define(TYPE_INTEGER , 2#00000111). %% 0000 0111 - Integer typedef
|
||||
-define(TYPE_BOOLEAN , 2#00010111). %% 0001 0111 - Boolean typedef
|
||||
-define(TYPE_LIST , 2#00100111). %% 0010 0111 | Type
|
||||
-define(TYPE_TUPLE , 2#00110111). %% 0011 0111 | Size | [Element Types]
|
||||
-define(TYPE_OBJECT , 2#01000111). %% 0100 0111 | ObjectType
|
||||
-define(TYPE_BITS , 2#01010111). %% 0101 0111 - Bits typedef
|
||||
-define(TYPE_MAP , 2#01100111). %% 0110 0111 | Type | Type
|
||||
-define(TYPE_STRING , 2#01110111). %% 0111 0111 - string typedef
|
||||
-define(TYPE_VARIANT , 2#10000111). %% 1000 0111 | Size | [Type]
|
||||
%% 1001 0111
|
||||
%% 1010 0111
|
||||
%% 1011 0111
|
||||
%% 1100 0111
|
||||
%% 1101 0111
|
||||
%% 1110 0111
|
||||
%% 1111 0111
|
||||
-define(LONG_TUPLE , 2#00001011). %% 0000 1011 | RLP encoded (size - 16) | [encoded elements],
|
||||
-define(SHORT_TUPLE , 2#1011). %% xxxx 1011 | [encoded elements] when 0 < size < 16
|
||||
%% 1111 Set below
|
||||
-define(LONG_LIST , 2#00011111). %% 0001 1111 - RLP encoded (length - 16) + [Elements]
|
||||
-define(MAP , 2#00101111). %% 0010 1111 - RLP encoded size + [encoded key, encoded value]
|
||||
-define(LONG_LIST , 2#00011111). %% 0001 1111 | RLP encoded (length - 16) | [encoded lements]
|
||||
-define(MAP , 2#00101111). %% 0010 1111 | RLP encoded size | [encoded key, encoded value]
|
||||
-define(EMPTY_TUPLE , 2#00111111). %% 0011 1111
|
||||
-define(POS_BITS , 2#01001111). %% 0100 1111 - RLP encoded integer (to be interpreted as bitfield)
|
||||
-define(POS_BITS , 2#01001111). %% 0100 1111 | RLP encoded integer (to be interpreted as bitfield)
|
||||
-define(EMPTY_STRING , 2#01011111). %% 0101 1111
|
||||
-define(POS_BIG_INT , 2#01101111). %% 0110 1111 - RLP encoded (integer - 64)
|
||||
-define(POS_BIG_INT , 2#01101111). %% 0110 1111 | RLP encoded (integer - 64)
|
||||
-define(FALSE , 2#01111111). %% 0111 1111
|
||||
%% %% 1000 1111 - FREE (Possibly for bytecode in the future.)
|
||||
-define(ADDRESS , 2#10011111). %% 1001 1111 - [32 bytes]
|
||||
-define(VARIANT , 2#10101111). %% 1010 1111 - encoded size + encoded tag + encoded values
|
||||
-define(OBJECT , 2#10011111). %% 1001 1111 | ObjectType | RLP encoded Array
|
||||
-define(VARIANT , 2#10101111). %% 1010 1111 | encoded size | encoded tag | [encoded values]
|
||||
-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(NEG_BIG_INT , 2#11101111). %% 1110 1111 - RLP encoded (integer - 64)
|
||||
-define(NEG_BIG_INT , 2#11101111). %% 1110 1111 | RLP encoded (integer - 64)
|
||||
-define(TRUE , 2#11111111). %% 1111 1111
|
||||
|
||||
-define(SHORT_TUPLE_SIZE, 16).
|
||||
-define(SHORT_LIST_SIZE , 16).
|
||||
-define(SMALL_INT_SIZE , 64).
|
||||
-define(SHORT_TUPLE_SIZE, 16).
|
||||
-define(SHORT_LIST_SIZE, 16).
|
||||
-define(SMALL_INT_SIZE, 64).
|
||||
-define(SHORT_STRING_SIZE, 64).
|
||||
|
||||
-define(POS_SIGN, 0).
|
||||
-define(NEG_SIGN, 1).
|
||||
|
||||
%% Object types
|
||||
-define(OTYPE_ADDRESS, 0).
|
||||
-define(OTYPE_HASH, 1).
|
||||
-define(OTYPE_SIGNATURE, 2).
|
||||
-define(OTYPE_CONTRACT, 3).
|
||||
-define(OTYPE_ORACLE, 4).
|
||||
-define(OTYPE_NAME, 5).
|
||||
-define(OTYPE_CHANNEL, 6).
|
||||
|
||||
%% --------------------------------------------------
|
||||
%% Serialize
|
||||
@ -106,7 +132,19 @@ serialize(String) when ?IS_FATE_STRING(String),
|
||||
Bytes = ?FATE_STRING_VALUE(String),
|
||||
<<?LONG_STRING, (aeser_rlp:encode(Bytes))/binary>>;
|
||||
serialize(?FATE_ADDRESS(Address)) when is_binary(Address) ->
|
||||
<<?ADDRESS, (aeser_rlp:encode(Address))/binary>>;
|
||||
<<?OBJECT, ?OTYPE_ADDRESS, (aeser_rlp:encode(Address))/binary>>;
|
||||
serialize(?FATE_HASH(Address)) when is_binary(Address) ->
|
||||
<<?OBJECT, ?OTYPE_HASH, (aeser_rlp:encode(Address))/binary>>;
|
||||
serialize(?FATE_SIGNATURE(Address)) when is_binary(Address) ->
|
||||
<<?OBJECT, ?OTYPE_SIGNATURE, (aeser_rlp:encode(Address))/binary>>;
|
||||
serialize(?FATE_CONTRACT(Address)) when is_binary(Address) ->
|
||||
<<?OBJECT, ?OTYPE_CONTRACT, (aeser_rlp:encode(Address))/binary>>;
|
||||
serialize(?FATE_ORACLE(Address)) when is_binary(Address) ->
|
||||
<<?OBJECT, ?OTYPE_ORACLE, (aeser_rlp:encode(Address))/binary>>;
|
||||
serialize(?FATE_NAME(Address)) when is_binary(Address) ->
|
||||
<<?OBJECT, ?OTYPE_NAME, (aeser_rlp:encode(Address))/binary>>;
|
||||
serialize(?FATE_CHANNEL(Address)) when is_binary(Address) ->
|
||||
<<?OBJECT, ?OTYPE_CHANNEL, (aeser_rlp:encode(Address))/binary>>;
|
||||
serialize(?FATE_TUPLE(T)) when size(T) > 0 ->
|
||||
S = size(T),
|
||||
L = tuple_to_list(T),
|
||||
@ -142,6 +180,79 @@ serialize(?FATE_VARIANT(Size, Tag, Values)) when 0 < Size, Size < 256,
|
||||
(serialize(?FATE_TUPLE(Values)))/binary
|
||||
>>.
|
||||
|
||||
%% -----------------------------------------------------
|
||||
|
||||
-spec serialize_type(aeb_fate_data:fate_type_type()) -> [byte()].
|
||||
serialize_type(integer) -> [?TYPE_INTEGER];
|
||||
serialize_type(boolean) -> [?TYPE_BOOLEAN];
|
||||
serialize_type({list, T}) -> [?TYPE_LIST | serialize_type(T)];
|
||||
serialize_type({tuple, Ts}) ->
|
||||
case length(Ts) of
|
||||
N when N =< 255 ->
|
||||
[?TYPE_TUPLE, N | [serialize_type(T) || T <- Ts]]
|
||||
end;
|
||||
serialize_type(address) -> [?TYPE_OBJECT, ?OTYPE_ADDRESS];
|
||||
serialize_type(hash) -> [?TYPE_OBJECT, ?OTYPE_HASH];
|
||||
serialize_type(signature) -> [?TYPE_OBJECT, ?OTYPE_SIGNATURE];
|
||||
serialize_type(contract) -> [?TYPE_OBJECT, ?OTYPE_CONTRACT];
|
||||
serialize_type(oracle) -> [?TYPE_OBJECT, ?OTYPE_ORACLE];
|
||||
serialize_type(name) -> [?TYPE_OBJECT, ?OTYPE_NAME];
|
||||
serialize_type(channel) -> [?TYPE_OBJECT, ?OTYPE_CHANNEL];
|
||||
serialize_type(bits) -> [?TYPE_BITS];
|
||||
serialize_type({map, K, V}) -> [?TYPE_MAP
|
||||
| serialize_type(K) ++ serialize_type(V)];
|
||||
serialize_type(string) -> [?TYPE_STRING];
|
||||
serialize_type({variant, ListOfVariants}) ->
|
||||
Size = length(ListOfVariants),
|
||||
if Size < 256 ->
|
||||
[?TYPE_VARIANT, Size | [serialize_type(T) || T <- ListOfVariants]]
|
||||
end.
|
||||
|
||||
|
||||
-spec deserialize_type(binary()) -> {aeb_fate_data:fate_type_type(), binary()}.
|
||||
deserialize_type(<<?TYPE_INTEGER, Rest/binary>>) -> {integer, Rest};
|
||||
deserialize_type(<<?TYPE_BOOLEAN, Rest/binary>>) -> {boolean, Rest};
|
||||
deserialize_type(<<?TYPE_LIST, Rest/binary>>) ->
|
||||
{T, Rest2} = deserialize_type(Rest),
|
||||
{{list, T}, Rest2};
|
||||
deserialize_type(<<?TYPE_TUPLE, N, Rest/binary>>) ->
|
||||
{Ts, Rest2} = deserialize_types(N, Rest, []),
|
||||
{{tuple, Ts}, Rest2};
|
||||
deserialize_type(<<TYPE_OBJECT, ObjectType, Rest/binary>>) ->
|
||||
case ObjectType of
|
||||
?OTYPE_ADDRESS -> {address, Rest};
|
||||
?OTYPE_HASH -> {hash, Rest};
|
||||
?OTYPE_SIGNATURE -> {signature, Rest};
|
||||
?OTYPE_CONTRACT -> {contract, Rest};
|
||||
?OTYPE_ORACLE -> {oracle, Rest};
|
||||
?OTYPE_NAME -> {name, Rest};
|
||||
?OTYPE_CHANNEL -> {channel, Rest}
|
||||
end;
|
||||
deserialize_type(<<?TYPE_BITS, Rest/binary>>) -> {bits, Rest};
|
||||
deserialize_type(<<?TYPE_MAP, Rest/binary>>) ->
|
||||
{K, Rest2} = deserialize_type(Rest),
|
||||
{V, Rest3} = deserialize_type(Rest2),
|
||||
{{map, K, V}, Rest3};
|
||||
deserialize_type(<<?TYPE_STRING, Rest/binary>>) ->
|
||||
{string, Rest};
|
||||
deserialize_type(<<?TYPE_VARIANT, Size, Rest/binary>>) ->
|
||||
{Variants, Rest2} = deserialize_variants(Size, Rest, []),
|
||||
{{variant, Variants}, Rest2}.
|
||||
|
||||
deserialize_variants(0, Rest, Variants) ->
|
||||
{lists:reverse(Variants), Rest};
|
||||
deserialize_variants(N, Rest, Variants) ->
|
||||
{T, Rest2} = deserialize_type(Rest),
|
||||
deserialize_variants(N-1, Rest2, [T|Variants]).
|
||||
|
||||
|
||||
|
||||
deserialize_types(0, Binary, Acc) ->
|
||||
{lists:reverse(Acc), Binary};
|
||||
deserialize_types(N, Binary, Acc) ->
|
||||
{T, Rest} = deserialize_type(Binary),
|
||||
deserialize_types(N-1, Rest, [T | Acc]).
|
||||
|
||||
|
||||
%% -----------------------------------------------------
|
||||
|
||||
@ -205,9 +316,19 @@ deserialize2(<<S:6, ?SHORT_STRING:2, Rest/binary>>) ->
|
||||
String = binary:part(Rest, 0, S),
|
||||
Rest2 = binary:part(Rest, byte_size(Rest), - (byte_size(Rest) - S)),
|
||||
{?MAKE_FATE_STRING(String), Rest2};
|
||||
deserialize2(<<?ADDRESS, Rest/binary>>) ->
|
||||
deserialize2(<<?OBJECT, ObjectType, Rest/binary>>) ->
|
||||
{A, Rest2} = aeser_rlp:decode_one(Rest),
|
||||
{?FATE_ADDRESS(A), Rest2};
|
||||
Val =
|
||||
case ObjectType of
|
||||
?OTYPE_ADDRESS -> ?FATE_ADDRESS(A);
|
||||
?OTYPE_HASH -> ?FATE_HASH(A);
|
||||
?OTYPE_SIGNATURE -> ?FATE_SIGNATURE(A);
|
||||
?OTYPE_CONTRACT -> ?FATE_CONTRACT(A);
|
||||
?OTYPE_ORACLE -> ?FATE_ORACLE(A);
|
||||
?OTYPE_NAME -> ?FATE_NAME(A);
|
||||
?OTYPE_CHANNEL -> ?FATE_CHANNEL(A)
|
||||
end,
|
||||
{Val, Rest2};
|
||||
deserialize2(<<?TRUE, Rest/binary>>) ->
|
||||
{?FATE_TRUE, Rest};
|
||||
deserialize2(<<?FALSE, Rest/binary>>) ->
|
||||
|
@ -393,9 +393,9 @@ gen_token(#{opname := OpName}) ->
|
||||
io_lib:format("~-28s: {token, {mnemonic, TokenLine, ~w}}.\n",
|
||||
[Name, OpName]).
|
||||
|
||||
insert_tokens_in_template(<<"###REPLACEWITHOPTOKENS###", Rest/binary >>, Tokens) ->
|
||||
insert_tokens_in_template(<<"%% ###REPLACEWITHOPTOKENS###", Rest/binary >>, Tokens) ->
|
||||
[Tokens, Rest];
|
||||
insert_tokens_in_template(<<"###REPLACEWITHNOTE###", Rest/binary >>, Tokens) ->
|
||||
insert_tokens_in_template(<<"%%% ###REPLACEWITHNOTE###", Rest/binary >>, Tokens) ->
|
||||
[
|
||||
"%%%\n"
|
||||
"%%% === === N O T E : This file is generated do not edit. === ===\n"
|
||||
|
Loading…
x
Reference in New Issue
Block a user