Pt 164325512 variant constants #130

Merged
zxq9 merged 9 commits from PT-164325512-variant-constants into fortuna 2019-03-01 21:05:25 +09:00
5 changed files with 231 additions and 47 deletions

113
README.md
View File

@ -1,9 +1,110 @@
aebytecode # aebytecode
===== An library and stand alone assembler for aeternity bytecode.
An OTP library This version supports Aevm bytecode and Fate bytecode.
Build ## Build
-----
$ make
## Fate Code
Fate code exists in 3 formats:
1. Fate byte code. This format is under consensus.
2. Fate assembler. This is a text represenation of fate code.
This is not under consensus and other
implemenation and toolchains could have
their own format.
3. Internal. This is an Erlang representation of fate code
Used by this particular engin implementation.
This library handles all tree representations.
The byte code format is described in a separate document.
The internal format is described in a separate document.
The text representation is described below.
### Fate Assembler Code
Assembler code can be read from a file.
The assembler has the following format:
Comments start with 2 semicolons and runs till end of line
`;; This is a comment`
Opcode mnemonics start with an upper case letter.
`DUP`
Identifiers start with a lower case letter
`an_identifier`
References to function arguments start with arg followed by an integer
`arg0`
References to variables/registers start with var followed by an integer
`var0`
References to stack postions is either a (for stack 0)
or start with stack followed by an integer
`stack1`
`a`
Immediate values can be of 9 types:
1. Integers as decimals: {Digits} or -{Digits}
`42`
`-2374683271468723648732648736498712634876147`
And integers as Hexadecimals:: 0x{Hexdigits}
`0x0deadbeef0`
2. addresses, a base58 encoded string starting with # followed by a number of base58chars
`#nv5B93FPzRHrGNmMdTDfGdd5xGZvep3MVSpJqzcQmMp59bBCv`
3. Boolean true or false
`true`
`false`
4. Strings "{Characters}"
`"Hello"`
5. Map { Key => Value }
`{}`
`{ 1 => { "foo" => true, "bar" => false}`
6. Lists [ Elements ]
`[]`
`[1, 2]`
7. Bit field < Bits > or !< Bits >
`<000>`
`<1010 1010>`
`<>`
`!<>`
8. Tuples ( Elements )
`()`
`(1, "foo")`
9. Variants: (| Size | Tag | ( Elements ) |)
`(| 42 | 12 | ( "foo", 12) |)`
Where
Digits: [0123456789]
Hexdigits: [0123456789abcdef]
base58char: [123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]
Characters: any printable ascii character 0..255 (except " no quoting yet)
Key: any value except for a map
Bits: 01 or space
Elements: Nothing or Value , Elements
Size: Digits (0 < Size < 256)
Tag: Digits (0 =< Tag < Size)
$ rebar3 compile

View File

@ -34,34 +34,47 @@
%%% stack1 %%% stack1
%%% a %%% a
%%% %%%
%%% Immediates can be of 9 types: %%% Immediate values can be of 9 types:
%%% 1. Integers %%% 1a. Integers as decimals: {Digits} or -{Digits}
%%% 42 %%% 42
%%% -2374683271468723648732648736498712634876147 %%% -2374683271468723648732648736498712634876147
%%% 2. Hexadecimal integers starting with 0x %%% 1b. Integers as Hexadecimals:: 0x{Hexdigits}
%%% 0x0deadbeef0 %%% 0x0deadbeef0
%%% 3. addresses, a 256-bit hash strings starting with # %%% 2. addresses, a base58 encoded string starting with #{base58char}
%%% followed by up to 64 hex chars %%% followed by up to 64 hex chars
%%% #00000deadbeef %%% #00000deadbeef
%%% 4. Boolean %%% 3. Boolean true or false
%%% true %%% true
%%% false %%% false
%%% 5. Strings %%% 4. Strings "{Characters}"
%%% "Hello" %%% "Hello"
%%% 6. Map %%% 5. Map { Key => Value }
%%% {} %%% {}
%%% { 1 => { "foo" => true, "bar" => false} %%% { 1 => { "foo" => true, "bar" => false}
%%% 7. Lists %%% 6. Lists [ Elements ]
%%% [] %%% []
%%% [1, 2] %%% [1, 2]
%%% 8. Bit field %%% 7. Bit field < Bits > or !< Bits >
%%% <000> %%% <000>
%%% <1010 1010> %%% <1010 1010>
%%% <> %%% <>
%%% !<> %%% !<>
%%% 9. Tuples %%% 8. Tuples ( Elements )
%%% () %%% ()
%%% (1, "foo") %%% (1, "foo")
%%% 9. Variants: (| Size | Tag | ( Elements ) |)
%%% (| 42 | 12 | ( "foo", 12) |)
%%%
%%% Where Digits: [0123456789]
%%% Hexdigits: [0123456789abcdef]
%%% base58char: [123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]
%%% Characters any printable ascii character 0..255 (except " no quoting yet)
%%% Key: any value except for a map
%%% Bits: 01 or space
%%% Elements: Nothing or Value , Elements
%%% Size: Digits
%%% Tag: Digits
%%%
%%% @end %%% @end
%%% Created : 21 Dec 2017 %%% Created : 21 Dec 2017
%%%------------------------------------------------------------------- %%%-------------------------------------------------------------------
@ -100,7 +113,7 @@ parse_function_call([{id,_,Name}, {'(',_}| Rest]) ->
to_args([{')', _}]) -> {[], []}; to_args([{')', _}]) -> {[], []};
to_args(Tokens) -> to_args(Tokens) ->
case to_data(Tokens) of case parse_value(Tokens) of
{Arg, [{',', _} | Rest]} -> {Arg, [{',', _} | Rest]} ->
{More, Rest2} = to_args(Rest), {More, Rest2} = to_args(Rest),
{[Arg|More], Rest2}; {[Arg|More], Rest2};
@ -108,13 +121,6 @@ to_args(Tokens) ->
{[Arg], Rest} {[Arg], Rest}
end. end.
to_data([{int,_line, Int}|Rest]) ->
{Int, Rest};
to_data([{boolean,_line, Bool}|Rest]) ->
{Bool, Rest};
to_data([{hash,_line, Hash}|Rest]) ->
{Hash, Rest}.
pp(FateCode) -> pp(FateCode) ->
Listing = to_asm(FateCode), Listing = to_asm(FateCode),
io_lib:format("~ts~n",[Listing]). io_lib:format("~ts~n",[Listing]).
@ -572,7 +578,16 @@ deserialize_type(<<6, Rest/binary>>) ->
{V, Rest3} = deserialize_type(Rest2), {V, Rest3} = deserialize_type(Rest2),
{{map, K, V}, Rest3}; {{map, K, V}, Rest3};
deserialize_type(<<7, Rest/binary>>) -> deserialize_type(<<7, Rest/binary>>) ->
{string, Rest}. {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]).
@ -616,8 +631,14 @@ to_bytecode([{int,_line, Int}|Rest], Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env, [{immediate, Int}|Code], Opts); to_bytecode(Rest, Address, Env, [{immediate, Int}|Code], Opts);
to_bytecode([{boolean,_line, Bool}|Rest], Address, Env, Code, Opts) -> to_bytecode([{boolean,_line, Bool}|Rest], Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env, [{immediate, Bool}|Code], Opts); to_bytecode(Rest, Address, Env, [{immediate, Bool}|Code], Opts);
to_bytecode([{hash,_line, Hash}|Rest], Address, Env, Code, Opts) -> to_bytecode([{string,_line, String}|Rest], Address, Env, Code, Opts) ->
to_bytecode(Rest, Address, Env, [{immediate, Hash}|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(Rest, Address, Env,
[{immediate, aeb_fate_data:make_address(Value)}|Code],
Opts);
to_bytecode([{id,_line, ID}|Rest], Address, Env, Code, Opts) -> to_bytecode([{id,_line, ID}|Rest], Address, Env, Code, Opts) ->
{Hash, Env2} = insert_symbol(ID, Env), {Hash, Env2} = insert_symbol(ID, Env),
to_bytecode(Rest, Address, Env2, [{immediate, Hash}|Code], Opts); to_bytecode(Rest, Address, Env2, [{immediate, Hash}|Code], Opts);
@ -631,6 +652,10 @@ to_bytecode([{'(',_line}|Rest], Address, Env, Code, Opts) ->
{Elements, Rest2} = parse_tuple(Rest), {Elements, Rest2} = parse_tuple(Rest),
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) ->
{Size, Tag, Values, Rest} = parse_variant(Tokens),
Variant = aeb_fate_data:make_variant(Size, Tag, Values),
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,
[{immediate, aeb_fate_data:make_bits(Bits)}|Code], Opts); [{immediate, aeb_fate_data:make_bits(Bits)}|Code], Opts);
@ -689,13 +714,35 @@ parse_tuple(Tokens) ->
end. end.
parse_variant([{start_variant,_line}
, {int,_line, Size}
, {'|',_}
, {int,_line, Tag}
, {'|',_}
, {'(',_}
| Rest]) when (Size > 0), (Tag < Size) ->
{Elements , [{end_variant, _} | Rest2]} = parse_tuple(Rest),
{Size, Tag, list_to_tuple(Elements), Rest2}.
parse_value([{int,_line, Int} | Rest]) -> {Int, Rest}; parse_value([{int,_line, Int} | Rest]) -> {Int, Rest};
parse_value([{boolean,_line, Bool} | Rest]) -> {Bool, Rest}; parse_value([{boolean,_line, Bool} | Rest]) -> {Bool, Rest};
parse_value([{hash,_line, Hash} | Rest]) -> {Hash, Rest}; parse_value([{hash,_line, Hash} | Rest]) -> {Hash, Rest};
parse_value([{'{',_line} | Rest]) -> parse_map(Rest); parse_value([{'{',_line} | Rest]) -> parse_map(Rest);
parse_value([{'[',_line} | Rest]) -> parse_list(Rest); parse_value([{'[',_line} | Rest]) -> parse_list(Rest);
parse_value([{'(',_line} | Rest]) -> parse_tuple(Rest). parse_value([{'(',_line} | Rest]) ->
{T, Rest2} = parse_tuple(Rest),
{aeb_fate_data:make_tuple(list_to_tuple(T)), Rest2};
parse_value([{bits,_line, Bits} | Rest]) ->
{aeb_fate_data:make_bits(Bits), Rest};
parse_value([{start_variant,_line}|_] = Tokens) ->
{Size, Tag, Values, Rest} = parse_variant(Tokens),
Variant = aeb_fate_data:make_variant(Size, Tag, Values),
{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}.
to_fun_def([{id, _, Name}, {'(', _} | Rest]) -> to_fun_def([{id, _, Name}, {'(', _} | Rest]) ->
{ArgsType, [{'to', _} | Rest2]} = to_arg_types(Rest), {ArgsType, [{'to', _} | Rest2]} = to_arg_types(Rest),
@ -732,7 +779,16 @@ to_type([{'{', _}, {id, _, "map"}, {',', _} | Rest]) ->
%% TODO: Error handling %% TODO: Error handling
{KeyType, [{',', _}| Rest2]} = to_type(Rest), {KeyType, [{',', _}| Rest2]} = to_type(Rest),
{ValueType, [{'}', _}| Rest3]} = to_type(Rest2), {ValueType, [{'}', _}| Rest3]} = to_type(Rest2),
{{map, KeyType, ValueType}, Rest3}. {{map, KeyType, ValueType}, Rest3};
to_type([{'{', _}
, {id, _, "variant"}
, {',', _}
, {'[', _}
| Rest]) ->
%% TODO: Error handling
{ElementTypes, [{'}', _}| Rest2]} = to_list_of_types(Rest),
{{variant, ElementTypes}, Rest2}.
to_list_of_types([{']', _} | Rest]) -> {[], Rest}; to_list_of_types([{']', _} | Rest]) -> {[], Rest};
to_list_of_types(Tokens) -> to_list_of_types(Tokens) ->
@ -756,8 +812,12 @@ serialize_type({tuple, Ts}) ->
serialize_type(address) -> [4]; serialize_type(address) -> [4];
serialize_type(bits) -> [5]; serialize_type(bits) -> [5];
serialize_type({map, K, V}) -> [6 | serialize_type(K) ++ serialize_type(V)]; serialize_type({map, K, V}) -> [6 | serialize_type(K) ++ serialize_type(V)];
serialize_type(string) -> [7]. serialize_type(string) -> [7];
serialize_type({variant, ListOfVariants}) ->
Size = length(ListOfVariants),
if Size < 256 ->
[8, Size | [serialize_type(T) || T <- ListOfVariants]]
end.
%% ------------------------------------------------------------------- %% -------------------------------------------------------------------

View File

@ -12,9 +12,10 @@ DIGIT = [0-9]
HEXDIGIT = [0-9a-fA-F] HEXDIGIT = [0-9a-fA-F]
LOWER = [a-z_] LOWER = [a-z_]
UPPER = [A-Z] UPPER = [A-Z]
BASE58 = [123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]
INT = {DIGIT}+ INT = {DIGIT}+
HEX = 0x{HEXDIGIT}+ HEX = 0x{HEXDIGIT}+
HASH = #{HEXDIGIT}+ HASH = #{BASE58}+
WS = [\000-\s] WS = [\000-\s]
ID = {LOWER}[a-zA-Z0-9_]* ID = {LOWER}[a-zA-Z0-9_]*
STRING = "[^"]*" STRING = "[^"]*"
@ -42,9 +43,9 @@ FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}.
-{INT} : -{INT} :
{token, {int, TokenLine, parse_int(TokenChars)}}. {token, {int, TokenLine, parse_int(TokenChars)}}.
{HASH} : {HASH} :
{token, {hash, TokenLine, parse_hash(TokenChars)}}. {token, {address, TokenLine, parse_hash(TokenChars)}}.
{STRING} : {STRING} :
{token, {hash, TokenLine, list_to_binary(TokenChars)}}. {token, {string, TokenLine, list_to_binary(TokenChars)}}.
{BITS} : {BITS} :
{token, {bits, TokenLine, bits(TokenChars)}}. {token, {bits, TokenLine, bits(TokenChars)}}.
@ -54,6 +55,8 @@ FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}.
\: : {token, {to, TokenLine}}. \: : {token, {to, TokenLine}}.
\=\> : {token, {arrow, TokenLine}}. \=\> : {token, {arrow, TokenLine}}.
\(\| : {token, {start_varaint, TokenLine}}.
\|\) : {token, {end_varaint, TokenLine}}.
, : {token, {',', TokenLine}}. , : {token, {',', TokenLine}}.
\( : {token, {'(', TokenLine}}. \( : {token, {'(', TokenLine}}.
@ -62,6 +65,7 @@ FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}.
\] : {token, {']', TokenLine}}. \] : {token, {']', TokenLine}}.
\{ : {token, {'{', TokenLine}}. \{ : {token, {'{', TokenLine}}.
\} : {token, {'}', TokenLine}}. \} : {token, {'}', TokenLine}}.
\| : {token, {'|', TokenLine}}.
;;.* : ;;.* :
{token, {comment, TokenLine, drop_prefix($;, TokenChars)}}. {token, {comment, TokenLine, drop_prefix($;, TokenChars)}}.
@ -98,8 +102,7 @@ parse_acc("a" ++ N) -> list_to_integer(N).
parse_hash("#" ++ Chars) -> parse_hash("#" ++ Chars) ->
N = list_to_integer(Chars, 16), base58_to_address(Chars).
<<N:256>>.
scan(S) -> scan(S) ->
string(S). string(S).
@ -117,3 +120,23 @@ bits([$> |_Rest], Acc) -> Acc;
bits([$0 | Rest], Acc) -> bits(Rest, Acc bsl 1); bits([$0 | Rest], Acc) -> bits(Rest, Acc bsl 1);
bits([$1 | Rest], Acc) -> bits(Rest, (Acc bsl 1) bor 1); bits([$1 | Rest], Acc) -> bits(Rest, (Acc bsl 1) bor 1);
bits([$ | Rest], Acc) -> bits(Rest, Acc). bits([$ | Rest], Acc) -> bits(Rest, Acc).
char_to_base58(C) ->
binary:at(<<0,1,2,3,4,5,6,7,8,0,0,0,0,0,0,0,9,10,11,12,13,14,15,16,0,17,
18,19,20,21,0,22,23,24,25,26,27,28,29,30,31,32,0,0,0,0,0,0,
33,34,35,36,37,38,39,40,41,42,43,0,44,45,46,47,48,49,50,51,
52,53,54,55,56,57>>, C-$1).
base58_to_integer(C, []) -> C;
base58_to_integer(C, [X | Xs]) ->
base58_to_integer(C * 58 + char_to_base58(X), Xs).
base58_to_integer([]) -> error;
base58_to_integer([Char]) -> char_to_base58(Char);
base58_to_integer([Char | Str]) ->
base58_to_integer(char_to_base58(Char), Str).
base58_to_address(Base58) ->
I = base58_to_integer(Base58),
Bin = <<I:256>>,
Bin.

View File

@ -144,7 +144,7 @@ format(?FATE_BITS(B)) when B < 0 ->
format(?FATE_VARIANT(Size, Tag, T)) -> format(?FATE_VARIANT(Size, Tag, T)) ->
["(| ", ["(| ",
lists:join("| ", [integer_to_list(Size), integer_to_list(Tag) | lists:join("| ", [integer_to_list(Size), integer_to_list(Tag) |
[format(E) || E <- erlang:tuple_to_list(T)]]), [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))), " }"];
@ -153,18 +153,13 @@ format(V) -> exit({not_a_fate_type, V}).
format_bits(0, Acc) -> Acc; format_bits(0, Acc) -> Acc;
format_bits(N, Acc) -> format_bits(N, Acc) ->
case N band 1 of Bit = $0 + (N band 1),
1 -> format_bits(N bsr 1, [$1|Acc]); format_bits(N bsr 1, [Bit|Acc]).
0 -> format_bits(N bsr 1, [$0|Acc])
end.
format_nbits(0, Acc) -> Acc; format_nbits(0, Acc) -> Acc;
format_nbits(N, Acc) -> format_nbits(N, Acc) ->
case N band 1 of Bit = $1 - (N band 1),
1 -> format_nbits(N bsr 1, [$0|Acc]); format_nbits(N bsr 1, [Bit|Acc]).
0 -> format_nbits(N bsr 1, [$1|Acc])
end.
format_list(List) -> format_list(List) ->
["[ ", lists:join(", ", [format(E) || E <- List]), " ]"]. ["[ ", lists:join(", ", [format(E) || E <- List]), " ]"].

View File

@ -65,4 +65,9 @@ FUNCTION tuple() : {tuple, [integer, boolean, string, {tuple, [integer, integer]
RETURNR (42, true, "FooBar", (1, 2)) RETURNR (42, true, "FooBar", (1, 2))
FUNCTION address() : address
RETURNR #deadbeef
;; Option(integer) = NONE | SOME(integer)
FUNCTION varaint() : {variant, [{tuple, []}, {tuple, [integer]}]}
RETURNR #deadbeef