Merge fortuna to master #136

Merged
gorillainduction merged 30 commits from fortuna into master 2019-03-13 18:57:29 +09:00
5 changed files with 115 additions and 35 deletions
Showing only changes of commit a35307f61b - Show all commits

View File

@ -53,6 +53,7 @@
, function_call/1 , function_call/1
, pp/1 , pp/1
, read_file/1 , read_file/1
, strip/1
, to_asm/1 , to_asm/1
, to_hexstring/1 , to_hexstring/1
]). ]).
@ -99,14 +100,36 @@ pp(FateCode) ->
to_asm(#{ functions := Functions to_asm(#{ functions := Functions
, symbols := Symbols} = _FateCode) -> , symbols := Symbols
lists:flatten( , annotations := Annotations} = _FateCode) ->
io_lib:format("~s",[ insert_comments(get_comments(Annotations), 1,
[format(lookup(Name, Symbols), lists:flatten(
Sig, io_lib:format("~s",
lists:sort(maps:to_list(CodeMap)), [format_functions(Functions, Symbols)]))).
Symbols) ||
{Name, {Sig, CodeMap}} <- maps:to_list(Functions)]])). insert_comments([{L,C}|Comments], L, String) ->
";; " ++ C ++ "\n" ++ insert_comments(Comments, L + 1, String);
insert_comments(Comments, L, [$\n|String]) ->
"\n" ++ insert_comments(Comments, L+1, String);
insert_comments(Comments, L, [C|Rest]) ->
[C|insert_comments(Comments, L, Rest)];
insert_comments([],_,[]) -> [];
insert_comments([{L,C}|Rest], _, []) ->
";; " ++ C ++ "\n" ++ insert_comments(Rest, L + 1, []).
format_functions(Functions, Symbols) ->
[format(lookup(Name, Symbols),
Sig,
lists:sort(maps:to_list(CodeMap)),
Symbols)
||
{Name, {Sig, CodeMap}} <- maps:to_list(Functions)].
format(Name, Sig, BBs, Symbols) -> format(Name, Sig, BBs, Symbols) ->
@ -320,6 +343,7 @@ asm_to_bytecode(AssemblerCode, Options) ->
Env = to_bytecode(Tokens, none, #{ functions => #{} Env = to_bytecode(Tokens, none, #{ functions => #{}
, symbols => #{} , symbols => #{}
, annotations => #{}
}, [], Options), }, [], Options),
ByteList = serialize(Env), ByteList = serialize(Env),
@ -329,7 +353,7 @@ asm_to_bytecode(AssemblerCode, Options) ->
ByteCode = << (aeb_rlp:encode(list_to_binary(ByteList)))/binary, ByteCode = << (aeb_rlp:encode(list_to_binary(ByteList)))/binary,
(aeb_rlp:encode(list_to_binary(Signatures)))/binary, (aeb_rlp:encode(list_to_binary(Signatures)))/binary,
(aeb_rlp:encode(SymbolTable))/binary, (aeb_rlp:encode(SymbolTable))/binary,
(aeb_rlp:encode(list_to_binary(Annotatations)))/binary (aeb_rlp:encode(Annotatations))/binary
>>, >>,
case proplists:lookup(pp_hex_string, Options) of case proplists:lookup(pp_hex_string, Options) of
@ -341,6 +365,10 @@ asm_to_bytecode(AssemblerCode, Options) ->
{Env, ByteCode}. {Env, ByteCode}.
strip(ByteCode) ->
{Code, _Rest} = aeb_rlp:decode_one(ByteCode),
Code.
bytecode_to_fate_code(Bytes, _Options) -> bytecode_to_fate_code(Bytes, _Options) ->
{ByteCode, Rest1} = aeb_rlp:decode_one(Bytes), {ByteCode, Rest1} = aeb_rlp:decode_one(Bytes),
{Signatures, Rest2} = aeb_rlp:decode_one(Rest1), {Signatures, Rest2} = aeb_rlp:decode_one(Rest1),
@ -517,15 +545,19 @@ deserialize_symbols(Table, Env) ->
?FATE_MAP_VALUE(SymbolTable) = aeb_fate_encoding:deserialize(Table), ?FATE_MAP_VALUE(SymbolTable) = aeb_fate_encoding:deserialize(Table),
Env#{symbols => SymbolTable}. Env#{symbols => SymbolTable}.
deserialize_annotations(_Annotations, Env) -> Env. deserialize_annotations(AnnotationsBin, Env) ->
?FATE_MAP_VALUE(Annotations) = aeb_fate_encoding:deserialize(AnnotationsBin),
Env#{annotations => Annotations}.
serialize_sigs(_Env) -> []. serialize_sigs(_Env) -> [].
serialize_symbol_table(#{ symbols := Symbols }) -> serialize_symbol_table(#{ symbols := Symbols }) ->
aeb_fate_encoding:serialize(aeb_fate_data:make_map(Symbols)). aeb_fate_encoding:serialize(aeb_fate_data:make_map(Symbols)).
serialize_annotations(_Env) -> serialize_annotations(#{ annotations := Annotations}) ->
[]. aeb_fate_encoding:serialize(aeb_fate_data:make_map(Annotations)).
@ -652,17 +684,6 @@ serialize_signature({Args, RetType}) ->
[serialize_type({tuple, Args}) | [serialize_type({tuple, Args}) |
serialize_type(RetType)]. serialize_type(RetType)].
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)].
deserialize_signature(Binary) -> deserialize_signature(Binary) ->
@ -697,6 +718,13 @@ to_hexstring(ByteList) ->
[io_lib:format("~2.16.0b", [X]) [io_lib:format("~2.16.0b", [X])
|| X <- ByteList]). || X <- ByteList]).
%% -------------------------------------------------------------------
%% Parser
%% Asm tokens -> Fate code env
%% -------------------------------------------------------------------
to_bytecode([{function,_line, 'FUNCTION'}|Rest], Address, Env, Code, Opts) -> to_bytecode([{function,_line, 'FUNCTION'}|Rest], Address, Env, Code, Opts) ->
Env2 = insert_fun(Address, Code, Env), Env2 = insert_fun(Address, Code, Env),
{Fun, Rest2} = to_fun_def(Rest), {Fun, Rest2} = to_fun_def(Rest),
@ -723,6 +751,10 @@ to_bytecode([{hash,_line, Hash}|Rest], Address, Env, 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);
to_bytecode([{comment, Line, Comment}|Rest], Address, Env, Code, Opts) ->
Env2 = insert_annotation(comment, Line, Comment, Env),
to_bytecode(Rest, Address, Env2, Code, Opts);
to_bytecode([], Address, Env, Code, Opts) -> to_bytecode([], Address, Env, Code, Opts) ->
Env2 = insert_fun(Address, Code, Env), Env2 = insert_fun(Address, Code, Env),
#{functions := Funs} = Env2, #{functions := Funs} = Env2,
@ -751,6 +783,9 @@ to_arg_types(Tokens) ->
{[Type], Rest} {[Type], Rest}
end. end.
%% Type handling
to_type([{id, _, "integer"} | Rest]) -> {integer, Rest}; to_type([{id, _, "integer"} | Rest]) -> {integer, Rest};
to_type([{id, _, "boolean"} | Rest]) -> {boolean, Rest}; to_type([{id, _, "boolean"} | Rest]) -> {boolean, Rest};
to_type([{id, _, "string"} | Rest]) -> {string, Rest}; to_type([{id, _, "string"} | Rest]) -> {string, Rest};
@ -781,6 +816,24 @@ to_list_of_types(Tokens) ->
end. end.
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)].
%% -------------------------------------------------------------------
%% Helper functions
%% -------------------------------------------------------------------
%% State handling
insert_fun(none, [], Env) -> Env; insert_fun(none, [], Env) -> Env;
insert_fun({Name, Type, RetType}, Code, #{functions := Functions} = Env) -> insert_fun({Name, Type, RetType}, Code, #{functions := Functions} = Env) ->
@ -794,6 +847,20 @@ mk_hash(Id) ->
{ok, <<A:8, B:8, C:8, D:8,_/binary>> } = aeb_blake2:blake2b(?HASH_BYTES, list_to_binary(Id)), {ok, <<A:8, B:8, C:8, D:8,_/binary>> } = aeb_blake2:blake2b(?HASH_BYTES, list_to_binary(Id)),
<<A,B,C,D>>. <<A,B,C,D>>.
%% Handle annotations
insert_annotation(comment, Line, Comment, #{annotations := A} = Env) ->
Key = aeb_fate_data:make_tuple({aeb_fate_data:make_string("comment"), Line}),
Value = aeb_fate_data:make_string(Comment),
Env#{annotations => A#{ Key => Value}}.
get_comments(Annotations) ->
[ {Line, Comment} ||
{?FATE_TUPLE({?FATE_STRING_VALUE("comment"), Line}),
?FATE_STRING_VALUE(Comment)} <- maps:to_list(Annotations)].
%% Symbols handling
insert_symbol(Id, Env) -> insert_symbol(Id, Env) ->
Hash = mk_hash(Id), Hash = mk_hash(Id),
insert_symbol(Id, Hash, Env). insert_symbol(Id, Hash, Env).
@ -809,6 +876,7 @@ insert_symbol(Id, Hash, #{symbols := Symbols} = Env) ->
, Hash => Id}}} , Hash => Id}}}
end. end.
%% Symbol table handling
lookup(Name, Symbols) -> lookup(Name, Symbols) ->
maps:get(Name, Symbols, Name). maps:get(Name, Symbols, Name).

View File

@ -161,6 +161,9 @@ FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}.
\{ : {token, {'{', TokenLine}}. \{ : {token, {'{', TokenLine}}.
\} : {token, {'}', TokenLine}}. \} : {token, {'}', TokenLine}}.
;;.* :
{token, {comment, TokenLine, drop_prefix($;, TokenChars)}}.
\. : skip_token. \. : skip_token.
@ -168,7 +171,7 @@ FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}.
{WS} : skip_token. {WS} : skip_token.
%% Comments (TODO: nested comments) %% Comments (TODO: nested comments)
;;.* : skip_token.
. : {error, "Unexpected token: " ++ TokenChars}. . : {error, "Unexpected token: " ++ TokenChars}.
@ -199,3 +202,6 @@ parse_hash("#" ++ Chars) ->
scan(S) -> scan(S) ->
string(S). string(S).
drop_prefix(C, [C|Rest]) ->
drop_prefix(C, Rest);
drop_prefix(_, Tail) -> Tail.

View File

@ -60,7 +60,6 @@ check_roundtrip(File) ->
io:format("~s~n", [AssemblerCode]), io:format("~s~n", [AssemblerCode]),
io:format("~s~n", [DissasmCode]), io:format("~s~n", [DissasmCode]),
{Env2, ByteCode2} = assemble(DissasmCode), {Env2, ByteCode2} = assemble(DissasmCode),
?assertEqual(ByteCode, ByteCode2). Code1 = aeb_fate_asm:strip(ByteCode),
Code2 = aeb_fate_asm:strip(ByteCode2),
?assertEqual(Code1, Code2).

View File

@ -1,9 +1,11 @@
;; CONTRACT jumpif ;; CONTRACT jumpif
FUNCTION skip(integer, integer) : integer FUNCTION skip(integer, integer) : integer
PUSH arg1 ;; BB : 0
PUSH 0 PUSH arg1
EQ a a arg0 PUSH 0
JUMPIF a 2 EQ a a arg0
INCA JUMPIF a 2
JUMP 2 ;; BB : 1
RETURN INCA
JUMP 2
RETURN

View File

@ -1,8 +1,10 @@
FUNCTION make_0tuple():{tuple, []} FUNCTION make_0tuple():{tuple, []}
;; BB : 0
TUPLE 0 TUPLE 0
RETURN RETURN
FUNCTION make_2tuple(integer, integer):{tuple, [integer, integer]} FUNCTION make_2tuple(integer, integer):{tuple, [integer, integer]}
;; BB : 0
PUSH arg0 PUSH arg0
PUSH arg1 PUSH arg1
TUPLE 2 TUPLE 2
@ -10,6 +12,7 @@ FUNCTION make_2tuple(integer, integer):{tuple, [integer, integer]}
FUNCTION make_5tuple(integer, integer, integer, integer, integer): FUNCTION make_5tuple(integer, integer, integer, integer, integer):
{tuple, [integer, integer, integer, integer, integer]} {tuple, [integer, integer, integer, integer, integer]}
;; BB : 0
PUSH arg0 PUSH arg0
PUSH arg1 PUSH arg1
PUSH arg2 PUSH arg2
@ -19,6 +22,7 @@ FUNCTION make_5tuple(integer, integer, integer, integer, integer):
RETURN RETURN
FUNCTION element1(integer, integer): integer FUNCTION element1(integer, integer): integer
;; BB : 0
PUSH arg0 PUSH arg0
PUSH arg1 PUSH arg1
TUPLE 2 TUPLE 2
@ -26,5 +30,6 @@ FUNCTION element1(integer, integer): integer
RETURN RETURN
FUNCTION element({tuple, [integer, integer]}, integer): integer FUNCTION element({tuple, [integer, integer]}, integer): integer
;; BB : 0
ELEMENT integer a arg1 arg0 ELEMENT integer a arg1 arg0
RETURN RETURN