Pt 164259596 generate format op #127
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,3 +16,4 @@ aefateasm
|
||||
include/aeb_fate_opcodes.hrl
|
||||
src/aeb_fate_code.erl
|
||||
src/aeb_fate_opcodes.erl
|
||||
src/aeb_fate_pp.erl
|
||||
|
21
Makefile
21
Makefile
@ -1,10 +1,10 @@
|
||||
|
||||
|
||||
GENERATED_SRC = src/aeb_fate_opcodes.erl src/aeb_fate_code.erl include/aeb_fate_opcodes.hrl src/aeb_fate_asm_scan.xrl src/aeb_fate_pp.erl
|
||||
GENERATOR_DEPS = ebin/aeb_fate_generate_ops.beam src/aeb_fate_asm_scan.template
|
||||
REBAR ?= rebar3
|
||||
|
||||
all: local
|
||||
|
||||
local: src/aeb_fate_opcodes.erl src/aeb_fate_code.erl include/aeb_fate_opcodes.hrl src/aeb_fate_asm_scan.xrl
|
||||
local: $(GENERATED_SRC)
|
||||
@$(REBAR) as local release
|
||||
|
||||
console: local
|
||||
@ -12,15 +12,12 @@ console: local
|
||||
|
||||
clean:
|
||||
@$(REBAR) clean
|
||||
rm -f src/aeb_fate_opcodes.erl
|
||||
rm -f src/aeb_fate_code.erl
|
||||
rm -f include/aeb_fate_opcodes.hrl
|
||||
rm -f $(GENERATED_SRC)
|
||||
rm -f ebin/*
|
||||
|
||||
dialyzer: local
|
||||
@$(REBAR) as local dialyzer
|
||||
|
||||
|
||||
|
||||
distclean: clean
|
||||
@rm -rf _build/
|
||||
|
||||
@ -30,12 +27,8 @@ eunit: local
|
||||
test: local
|
||||
@$(REBAR) as local eunit
|
||||
|
||||
|
||||
ebin/aeb_fate_generate_ops.beam: src/aeb_fate_generate_ops.erl ebin
|
||||
ebin/%.beam: src/%.erl
|
||||
erlc -o $(dir $@) $<
|
||||
|
||||
src/aeb_fate_opcodes.erl src/aeb_fate_code.erl include/aeb_fate_opcodes.hrl src/aeb_fate_asm_scan.xrl: ebin/aeb_fate_generate_ops.beam
|
||||
$(GENERATED_SRC): $(GENERATOR_DEPS)
|
||||
erl -pa ebin/ -noshell -s aeb_fate_generate_ops gen_and_halt src/ include/
|
||||
|
||||
ebin:
|
||||
mkdir ebin
|
||||
|
0
ebin/.gitkeep
Normal file
0
ebin/.gitkeep
Normal file
@ -45,5 +45,8 @@
|
||||
"robocopy \"%REBAR_BUILD_DIR%/bin/\" ./ aefateasm* "
|
||||
"/njs /njh /nfl /ndl & exit /b 0"} % silence things
|
||||
]}
|
||||
]}]}.
|
||||
|
||||
]},
|
||||
{eqc, [{erl_opts, [{parse_transform, eqc_cover}]},
|
||||
{extra_src_dirs, ["quickcheck"]} %% May not be called eqc!
|
||||
]}
|
||||
]}.
|
||||
|
@ -2,6 +2,21 @@
|
||||
%%% @copyright (C) 2019, Aeternity Anstalt
|
||||
%%% @doc Assembler for Fate machine 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 here:
|
||||
%%%
|
||||
%%% 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
|
||||
@ -33,14 +48,15 @@
|
||||
%%% false
|
||||
%%% 5. Strings
|
||||
%%% "Hello"
|
||||
%%% 6. Empty map
|
||||
%%% 6. Map
|
||||
%%% {}
|
||||
%%% { 1 => { "foo" => true, "bar" => false}
|
||||
%%% 7. Lists
|
||||
%%% []
|
||||
%%% [1, 2]
|
||||
%%% 8. Bit field
|
||||
%%% <000>
|
||||
%%% <1010>
|
||||
%%% <1010 1010>
|
||||
%%% <>
|
||||
%%% !<>
|
||||
%%% 9. Tuples
|
||||
@ -157,14 +173,6 @@ format_arg_types([T|Ts]) ->
|
||||
, ", "
|
||||
, format_arg_types(Ts)].
|
||||
|
||||
format_arg({immediate, I}) ->
|
||||
aeb_fate_data:format(I);
|
||||
format_arg({arg, N}) -> io_lib:format("arg~p", [N]);
|
||||
format_arg({var, N}) -> io_lib:format("var~p", [N]);
|
||||
format_arg({stack, 0}) -> "a";
|
||||
format_arg({stack, N}) -> io_lib:format("a~p", [N]).
|
||||
|
||||
|
||||
format_type(T) ->
|
||||
%% TODO: Limit to ok types.
|
||||
io_lib:format("~p", [T]).
|
||||
@ -180,157 +188,10 @@ format_code([], _) ->
|
||||
"";
|
||||
format_code([Op|Rest], Symbols) ->
|
||||
[" ",
|
||||
format_op(Op, Symbols),
|
||||
aeb_fate_pp:format_op(Op, Symbols),
|
||||
"\n",
|
||||
format_code(Rest, Symbols)].
|
||||
|
||||
format_op('RETURN', _) -> "RETURN";
|
||||
format_op({'RETURNR', Arg}, _) -> ["RETURNR ", format_arg(Arg)];
|
||||
format_op({'CALL', {immediate, Function}}, Symbols) ->
|
||||
["CALL ", lookup(Function, Symbols)];
|
||||
format_op({'CALL_T', {immediate, Function}}, Symbols) ->
|
||||
["CALL_T ", lookup(Function, Symbols)];
|
||||
format_op({'CALL_R', {immediate, Contract}, {immediate, Function}}, Symbols) ->
|
||||
["CALL_R ", lookup(Contract, Symbols), "." , lookup(Function, Symbols)];
|
||||
format_op({'CALL_R', Contract, {immediate, Function}}, Symbols) ->
|
||||
["CALL_R ", format_arg(Contract), "." , lookup(Function, Symbols)];
|
||||
format_op({'CALL_TR', {immediate, Contract}, {immediate, Function}}, Symbols) ->
|
||||
["CALL_TR ", lookup(Contract, Symbols), "." , lookup(Function, Symbols)];
|
||||
format_op({'CALL_TR', Contract, {immediate, Function}}, Symbols) ->
|
||||
["CALL_TR ", format_arg(Contract), "." , lookup(Function, Symbols)];
|
||||
format_op({'JUMP', {immediate, BB}}, _) ->
|
||||
["JUMP ", io_lib:format("~p", [BB])];
|
||||
format_op({'JUMPIF', Arg, {immediate, BB}}, _) ->
|
||||
["JUMPIF ", format_arg(Arg), " ", io_lib:format("~p", [BB])];
|
||||
format_op({'SWITCH_V2', Variant, {immediate, BB1}, {immediate, BB2}}, _) ->
|
||||
["SWITCH_V2 ", format_arg(Variant), " ", BB1, " ", BB2];
|
||||
format_op({'SWITCH_V3', Variant, {immediate, BB1}, {immediate, BB2}, {immediate, BB3}}, _) ->
|
||||
["SWITCH_V2 ", format_arg(Variant), " ", BB1, " ", BB2, " ", BB3];
|
||||
format_op({'SWITCH_VN', Variant, BBs}, _) ->
|
||||
["SWITCH_VN ", format_arg(Variant), [[" ", BB] || {immedate, BB} <- BBs]];
|
||||
format_op({'PUSH', Arg0}, _) ->
|
||||
["PUSH ", format_arg(Arg0)];
|
||||
format_op('INCA', _) -> "INCA";
|
||||
format_op({'INC', Name}, _) -> ["INC ", format_arg(Name)];
|
||||
format_op({'DEC', Name}, _) -> ["DEC ", format_arg(Name)];
|
||||
format_op('DECA', _) -> "DECA";
|
||||
format_op({'ADD', Dest, Left, Right}, _) ->
|
||||
["ADD ", format_arg(Dest), " ", format_arg(Left), " ", format_arg(Right)];
|
||||
format_op({'SUB', Dest, Left, Right}, _) ->
|
||||
["SUB ", format_arg(Dest), " ", format_arg(Left), " ", format_arg(Right)];
|
||||
format_op({'MUL', Dest, Left, Right}, _) ->
|
||||
["MUL ", format_arg(Dest), " ", format_arg(Left), " ", format_arg(Right)];
|
||||
format_op({'DIV', Dest, Left, Right}, _) ->
|
||||
["DIV ", format_arg(Dest), " ", format_arg(Left), " ", format_arg(Right)];
|
||||
format_op({'MOD', Dest, Left, Right}, _) ->
|
||||
["MOD ", format_arg(Dest), " ", format_arg(Left), " ", format_arg(Right)];
|
||||
format_op({'POW', Dest, Left, Right}, _) ->
|
||||
["POW ", format_arg(Dest), " ", format_arg(Left), " ", format_arg(Right)];
|
||||
format_op({'LT', Dest, Left, Right}, _) ->
|
||||
["LT ", format_arg(Dest), " ", format_arg(Left), " ", format_arg(Right)];
|
||||
format_op({'GT', Dest, Left, Right}, _) ->
|
||||
["GT ", format_arg(Dest), " ", format_arg(Left), " ", format_arg(Right)];
|
||||
format_op({'ELT', Dest, Left, Right}, _) ->
|
||||
["ELT ", format_arg(Dest), " ", format_arg(Left), " ", format_arg(Right)];
|
||||
format_op({'EGT', Dest, Left, Right}, _) ->
|
||||
["EGT ", format_arg(Dest), " ", format_arg(Left), " ", format_arg(Right)];
|
||||
format_op({'EQ', Dest, Left, Right}, _) ->
|
||||
["EQ ", format_arg(Dest), " ", format_arg(Left), " ", format_arg(Right)];
|
||||
format_op({'NEQ', Dest, Left, Right}, _) ->
|
||||
["NEQ ", format_arg(Dest), " ", format_arg(Left), " ", format_arg(Right)];
|
||||
format_op({'AND', Dest, Left, Right}, _) ->
|
||||
["AND ", format_arg(Dest), " ", format_arg(Left), " ", format_arg(Right)];
|
||||
format_op({'OR', Dest, Left, Right}, _) ->
|
||||
["OR ", format_arg(Dest), " ", format_arg(Left), " ", format_arg(Right)];
|
||||
format_op({'NOT', Dest, Name}, _) ->
|
||||
["NOT ", format_arg(Dest), " ", format_arg(Name)];
|
||||
format_op({'TUPLE', {immediate, Size}}, _) ->
|
||||
["TUPLE ", io_lib:format("~p", [Size])];
|
||||
format_op({'ELEMENT', Type, Dest, Which, Tuple}, _) ->
|
||||
[ "ELEMENT "
|
||||
, io_lib:format("~p ", [Type])
|
||||
, format_arg(Dest), " "
|
||||
, format_arg(Which), " "
|
||||
, format_arg(Tuple)];
|
||||
format_op({'MAP_EMPTY', Dest}, _) ->
|
||||
["MAP_EMPTY ", format_arg(Dest)];
|
||||
format_op({'MAP_LOOKUP', Dest, Map, Key}, _) ->
|
||||
["MAP_LOOKUP ", format_arg(Dest), " "
|
||||
, format_arg(Map), " ", format_arg(Key)];
|
||||
format_op({'MAP_DELETE', Dest, Map, Key}, _) ->
|
||||
["MAP_DELETE ", format_arg(Dest), " "
|
||||
, format_arg(Map), " ", format_arg(Key)];
|
||||
format_op({'MAP_LOOKUPD', Dest, Map, Key, Default}, _) ->
|
||||
["MAP_LOOKUPD ", format_arg(Dest), " "
|
||||
, format_arg(Map), " ", format_arg(Key), " ", format_arg(Default)];
|
||||
format_op({'MAP_UPDATE', Dest, Map, Key, Value}, _) ->
|
||||
["MAP_UPDATE ", format_arg(Dest), " "
|
||||
, format_arg(Map), " ", format_arg(Key), " ", format_arg(Value)];
|
||||
format_op({'MAP_MEMBER', Dest, Map, Key}, _) ->
|
||||
["MAP_MEMBER ", format_arg(Dest), " "
|
||||
, format_arg(Map), " ", format_arg(Key)];
|
||||
format_op({'MAP_FROM_LIST', Dest, List}, _) ->
|
||||
["MAP_FROM_LIST ", format_arg(Dest), " ", format_arg(List)];
|
||||
format_op({'NIL', Dest}, _) ->
|
||||
["NIL ", format_arg(Dest)];
|
||||
format_op({'IS_NIL', Dest, List}, _) ->
|
||||
["IS_NIL ", format_arg(Dest), " ", format_arg(List)];
|
||||
format_op({'CONS', Dest, Hd, Tl}, _) ->
|
||||
["CONS ", format_arg(Dest), " ", format_arg(Hd), " ", format_arg(Tl)];
|
||||
format_op({'HD', Dest, List}, _) ->
|
||||
["HD ", format_arg(Dest), " ", format_arg(List)];
|
||||
format_op({'TL', Dest, List}, _) ->
|
||||
["TL ", format_arg(Dest), " ", format_arg(List)];
|
||||
format_op({'LENGTH', Dest, List}, _) ->
|
||||
["LENGTH ", format_arg(Dest), " ", format_arg(List)];
|
||||
format_op({'STR_EQ', Dest, Str1, Str2}, _) ->
|
||||
["STR_EQ ", format_arg(Dest), " ", format_arg(Str1), format_arg(Str2)];
|
||||
format_op({'STR_JOIN', Dest, Str1, Str2}, _) ->
|
||||
["STR_JOIN ", format_arg(Dest), " ", format_arg(Str1), format_arg(Str2)];
|
||||
format_op({'INT_TO_STR', Dest, Str}, _) ->
|
||||
["INT_TO_STR ", format_arg(Dest), " ", format_arg(Str)];
|
||||
format_op({'ADDR_TO_STR', Dest, Str}, _) ->
|
||||
["ADDR_TO_STR ", format_arg(Dest), " ", format_arg(Str)];
|
||||
format_op({'STR_REVERSE', Dest, Str}, _) ->
|
||||
["STR_REVERSE ", format_arg(Dest), " ", format_arg(Str)];
|
||||
format_op({'INT_TO_ADDR', Dest, Str}, _) ->
|
||||
["INT_TO_ADDR ", format_arg(Dest), " ", format_arg(Str)];
|
||||
format_op({'VARIANT_TEST', Dest, Variant, Tag}, _) ->
|
||||
["VARIANT_TEST ", format_arg(Dest), " ", format_arg(Variant), " ", format_arg(Tag)];
|
||||
format_op({'VARIANT_ELEMENT', Dest, Variant, Index}, _) ->
|
||||
["VARIANT_ELEMENT ", format_arg(Dest), " ", format_arg(Variant), " ", format_arg(Index)];
|
||||
format_op({'VARIANT', Dest, SizeA, TagA, ElementsA}, _) ->
|
||||
["VARIANT ", format_arg(Dest), " ", format_arg(SizeA), " "
|
||||
, format_arg(TagA), " ", format_arg(ElementsA)];
|
||||
format_op('BITS_NONEA', _) -> "BITS_NONEA ";
|
||||
format_op({'BITS_NONE', To}, _) -> ["BITS_NONE ", format_arg(To)];
|
||||
format_op('BITS_ALLA', _) -> "BITS_ALLA";
|
||||
format_op({'BITS_ALL', To}, _) -> ["BITS_ALL ", format_arg(To)];
|
||||
format_op({'BITS_ALL_N', To, N}, _) ->
|
||||
["BITS_ALL_N ", format_arg(To), " ", format_arg(N)];
|
||||
format_op({'BITS_SET', To, Bits, Bit}, _) ->
|
||||
["BITS_SET ", format_arg(To), " ", format_arg(Bits), " ", format_arg(Bit)];
|
||||
format_op({'BITS_CLEAR', To, Bits, Bit}, _) ->
|
||||
["BITS_CLEAR ", format_arg(To), " ", format_arg(Bits), " ", format_arg(Bit)];
|
||||
format_op({'BITS_TEST', To, Bits, Bit}, _) ->
|
||||
["BITS_TEST ", format_arg(To), " ", format_arg(Bits), " ", format_arg(Bit)];
|
||||
format_op({'BITS_SUM', To, Bits}, _) ->
|
||||
["BITS_SUM ", format_arg(To), " ", format_arg(Bits)];
|
||||
format_op({'BITS_OR', To, Bits, Bit}, _) ->
|
||||
["BITS_OR ", format_arg(To), " ", format_arg(Bits), " ", format_arg(Bit)];
|
||||
format_op({'BITS_AND', To, Bits, Bit}, _) ->
|
||||
["BITS_AND ", format_arg(To), " ", format_arg(Bits), " ", format_arg(Bit)];
|
||||
format_op({'BITS_DIFF', To, Bits, Bit}, _) ->
|
||||
["BITS_DIFF ", format_arg(To), " ", format_arg(Bits), " ", format_arg(Bit)];
|
||||
format_op('DUPA', _) -> "DUPA";
|
||||
format_op({'DUP', {immediate, N}}, _) ->
|
||||
["DUP ", io_lib:format("~p", [N])];
|
||||
format_op({'POP', Dest}, _) ->
|
||||
["POP ", format_arg(Dest)];
|
||||
format_op({'STORE', Var, What}, _) ->
|
||||
["STORE ", format_arg(Var), " ", format_arg(What)];
|
||||
format_op('NOP', _) -> "NOP".
|
||||
|
||||
|
||||
read_file(Filename) ->
|
||||
{ok, File} = file:read_file(Filename),
|
||||
@ -709,7 +570,11 @@ 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}.
|
||||
{{map, K, V}, Rest3};
|
||||
deserialize_type(<<7, Rest/binary>>) ->
|
||||
{string, Rest}.
|
||||
|
||||
|
||||
|
||||
deserialize_types(0, Binary, Acc) ->
|
||||
{lists:reverse(Acc), Binary};
|
||||
@ -756,6 +621,19 @@ to_bytecode([{hash,_line, Hash}|Rest], Address, Env, 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);
|
||||
to_bytecode([{'{',_line}|Rest], Address, Env, Code, Opts) ->
|
||||
{Map, Rest2} = parse_map(Rest),
|
||||
to_bytecode(Rest2, Address, Env, [{immediate, Map}|Code], Opts);
|
||||
to_bytecode([{'[',_line}|Rest], Address, Env, Code, Opts) ->
|
||||
{List, Rest2} = parse_list(Rest),
|
||||
to_bytecode(Rest2, Address, Env, [{immediate, List}|Code], Opts);
|
||||
to_bytecode([{'(',_line}|Rest], Address, Env, Code, Opts) ->
|
||||
{Elements, Rest2} = parse_tuple(Rest),
|
||||
Tuple = aeb_fate_data:make_tuple(list_to_tuple(Elements)),
|
||||
to_bytecode(Rest2, Address, Env, [{immediate, Tuple}|Code], Opts);
|
||||
to_bytecode([{bits,_line, Bits}|Rest], Address, Env, Code, Opts) ->
|
||||
to_bytecode(Rest, Address, Env, [{immediate, Bits}|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);
|
||||
@ -772,6 +650,51 @@ to_bytecode([], Address, Env, Code, Opts) ->
|
||||
end,
|
||||
Env2.
|
||||
|
||||
parse_map([{'}',_line}|Rest]) ->
|
||||
{#{}, Rest};
|
||||
parse_map(Tokens) ->
|
||||
{Key, [{arrow, _} | Rest]} = parse_value(Tokens),
|
||||
{Value, Rest2} = parse_value(Rest),
|
||||
case Rest2 of
|
||||
[{',',_} | Rest3] ->
|
||||
{Map, Rest4} = parse_map(Rest3),
|
||||
{Map#{Key => Value}, Rest4};
|
||||
[{'}',_} | Rest3] ->
|
||||
{#{Key => Value}, Rest3}
|
||||
end.
|
||||
|
||||
parse_list([{']',_line}|Rest]) ->
|
||||
{[], Rest};
|
||||
parse_list(Tokens) ->
|
||||
{Head , Rest} = parse_value(Tokens),
|
||||
case Rest of
|
||||
[{',',_} | Rest2] ->
|
||||
{Tail, Rest3} = parse_list(Rest2),
|
||||
{[Head | Tail], Rest3};
|
||||
[{']',_} | Rest3] ->
|
||||
{[Head], Rest3}
|
||||
end.
|
||||
|
||||
parse_tuple([{')',_line}|Rest]) ->
|
||||
{[], Rest};
|
||||
parse_tuple(Tokens) ->
|
||||
{Head , Rest} = parse_value(Tokens),
|
||||
case Rest of
|
||||
[{',',_} | Rest2] ->
|
||||
{Tail, Rest3} = parse_tuple(Rest2),
|
||||
{[Head | Tail], Rest3};
|
||||
[{')',_} | Rest3] ->
|
||||
{[Head], Rest3}
|
||||
end.
|
||||
|
||||
|
||||
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]) -> parse_tuple(Rest).
|
||||
|
||||
|
||||
to_fun_def([{id, _, Name}, {'(', _} | Rest]) ->
|
||||
{ArgsType, [{'to', _} | Rest2]} = to_arg_types(Rest),
|
||||
@ -829,9 +752,11 @@ serialize_type({tuple, Ts}) ->
|
||||
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(address) -> [4];
|
||||
serialize_type(bits) -> [5];
|
||||
serialize_type({map, K, V}) -> [6 | serialize_type(K) ++ serialize_type(V)];
|
||||
serialize_type(string) -> [7].
|
||||
|
||||
|
||||
|
||||
%% -------------------------------------------------------------------
|
||||
|
@ -17,7 +17,8 @@ HEX = 0x{HEXDIGIT}+
|
||||
HASH = #{HEXDIGIT}+
|
||||
WS = [\000-\s]
|
||||
ID = {LOWER}[a-zA-Z0-9_]*
|
||||
|
||||
STRING = "[^"]*"
|
||||
BITS = (\!)?\<[\s01]*\>
|
||||
|
||||
Rules.
|
||||
arg{INT} : {token, {arg, TokenLine, parse_arg(TokenChars)}}.
|
||||
@ -38,13 +39,22 @@ FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}.
|
||||
{token, {int, TokenLine, parse_hex(TokenChars)}}.
|
||||
{INT} :
|
||||
{token, {int, TokenLine, parse_int(TokenChars)}}.
|
||||
-{INT} :
|
||||
{token, {int, TokenLine, parse_int(TokenChars)}}.
|
||||
{HASH} :
|
||||
{token, {hash, TokenLine, parse_hash(TokenChars)}}.
|
||||
{STRING} :
|
||||
{token, {hash, TokenLine, list_to_binary(TokenChars)}}.
|
||||
{BITS} :
|
||||
{token, {bits, TokenLine, bits(TokenChars)}}.
|
||||
|
||||
|
||||
%% Symbols
|
||||
\-\> : {token, {'to', TokenLine}}.
|
||||
\: : {token, {'to', TokenLine}}.
|
||||
\-\> : {token, {to, TokenLine}}.
|
||||
\: : {token, {to, TokenLine}}.
|
||||
|
||||
\=\> : {token, {arrow, TokenLine}}.
|
||||
|
||||
, : {token, {',', TokenLine}}.
|
||||
\( : {token, {'(', TokenLine}}.
|
||||
\) : {token, {')', TokenLine}}.
|
||||
@ -97,3 +107,13 @@ scan(S) ->
|
||||
drop_prefix(C, [C|Rest]) ->
|
||||
drop_prefix(C, Rest);
|
||||
drop_prefix(_, Tail) -> Tail.
|
||||
|
||||
bits([$!, $< | Rest]) ->
|
||||
bits(Rest, -1);
|
||||
bits([$< | Rest]) ->
|
||||
bits(Rest, 0).
|
||||
|
||||
bits([$> |_Rest], Acc) -> Acc;
|
||||
bits([$0 | Rest], Acc) -> bits(Rest, Acc bsl 1);
|
||||
bits([$1 | Rest], Acc) -> bits(Rest, (Acc bsl 1) bor 1);
|
||||
bits([$ | Rest], Acc) -> bits(Rest, Acc).
|
||||
|
@ -23,7 +23,7 @@
|
||||
| {map, fate_type(), fate_type()}
|
||||
| {tuple, [fate_type()]}
|
||||
| address
|
||||
| bits
|
||||
| bits
|
||||
| {variant, integer()}.
|
||||
|
||||
|
||||
@ -133,30 +133,25 @@ format(?FATE_TRUE) -> "true";
|
||||
format(?FATE_FALSE) -> "false";
|
||||
format(?FATE_NIL) -> "[]";
|
||||
format(L) when ?IS_FATE_LIST(L) -> format_list(?FATE_LIST_VALUE(L));
|
||||
format(?FATE_UNIT) -> "unit";
|
||||
format(?FATE_UNIT) -> "()";
|
||||
format(?FATE_TUPLE(T)) ->
|
||||
"{ " ++ [format(E) ++ " " || E <- erlang:tuple_to_list(T)] ++ "}";
|
||||
["( ", lists:join(", ", [ format(E) || E <- erlang:tuple_to_list(T)]), " )"];
|
||||
format(S) when ?IS_FATE_STRING(S) -> [S];
|
||||
format(?FATE_VARIANT(Size, Tag, T)) ->
|
||||
"( " ++ integer_to_list(Size) ++ ", "
|
||||
++ integer_to_list(Tag) ++ ", "
|
||||
++ [format(E) ++ " " || E <- erlang:tuple_to_list(T)]
|
||||
++ " )";
|
||||
["(| ",
|
||||
lists:join("| ", [integer_to_list(Size), integer_to_list(Tag) |
|
||||
[format(E) || E <- erlang:tuple_to_list(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_kvs(maps:to_list(?FATE_MAP_VALUE(M))), " }"];
|
||||
format(?FATE_ADDRESS(Address)) -> ["#", address_to_base58(Address)];
|
||||
format(V) -> exit({not_a_fate_type, V}).
|
||||
|
||||
format_list([]) -> " ]";
|
||||
format_list([E]) -> format(E) ++ " ]";
|
||||
format_list([H|T]) -> format(H) ++ ", " ++ format_list(T).
|
||||
format_list(List) ->
|
||||
["[ ", lists:join(", ", [format(E) || E <- List]), " ]"].
|
||||
|
||||
format_kvs([]) -> "";
|
||||
format_kvs([{K,V}]) -> "( " ++ format(K) ++ " => " ++ format(V) ++ " )";
|
||||
format_kvs([{K,V} | Rest]) ->
|
||||
"( " ++ format(K) ++ " => " ++ format(V) ++ " ), " ++ format_kvs(Rest).
|
||||
format_kvs(List) ->
|
||||
lists:join(", ", [ [format(K), " => ", format(V)] || {K, V} <- List]).
|
||||
|
||||
|
||||
%% -- Local base 58 library
|
||||
|
@ -128,7 +128,7 @@ serialize(L) when ?IS_FATE_LIST(L) ->
|
||||
<<?LONG_LIST, Val/binary, Rest/binary>>
|
||||
end;
|
||||
serialize(Map) when ?IS_FATE_MAP(Map) ->
|
||||
L = [{_K,_V}|_] = maps:to_list(?FATE_MAP_VALUE(Map)),
|
||||
L = [{_K,_V}|_] = lists:sort(maps:to_list(?FATE_MAP_VALUE(Map))),
|
||||
Size = length(L),
|
||||
%% TODO: check all K same type, and all V same type
|
||||
%% check K =/= map
|
||||
@ -136,10 +136,8 @@ serialize(Map) when ?IS_FATE_MAP(Map) ->
|
||||
<<?MAP,
|
||||
(rlp_integer(Size))/binary,
|
||||
(Elements)/binary>>;
|
||||
serialize(?FATE_VARIANT(Size, Tag, Values)) when 0 =< Size
|
||||
, Size < 256
|
||||
, 0 =< Tag
|
||||
, Tag < Size ->
|
||||
serialize(?FATE_VARIANT(Size, Tag, Values)) when 0 < Size, Size < 256,
|
||||
0 =< Tag, Tag < Size ->
|
||||
<<?VARIANT, Size:8, Tag:8,
|
||||
(serialize(?FATE_TUPLE(Values)))/binary
|
||||
>>.
|
||||
|
@ -18,7 +18,8 @@ generate(Src, Include) ->
|
||||
generate_header_file(HrlFile, Ops),
|
||||
generate_opcodes_ops(aeb_fate_opcodes, HrlFile, Src, Ops),
|
||||
generate_code_ops(aeb_fate_code, Src, Ops),
|
||||
generate_scanner("aeb_fate_asm_scan.template", "aeb_fate_asm_scan.xrl", Src, Ops).
|
||||
generate_scanner("aeb_fate_asm_scan.template", "aeb_fate_asm_scan.xrl", Src, Ops),
|
||||
gen_asm_pp(aeb_fate_pp, Src, Ops).
|
||||
|
||||
%% TODO: Some real gas numbers...
|
||||
ops_defs() ->
|
||||
@ -398,5 +399,103 @@ insert_tokens_in_template(<<"###REPLACEWITHNOTE###", Rest/binary >>, Tokens) ->
|
||||
insert_tokens_in_template(<<B,Rest/binary>>, Tokens) ->
|
||||
[B|insert_tokens_in_template(Rest, Tokens)].
|
||||
|
||||
gen_asm_pp(Module, Path, Ops) ->
|
||||
Filename = filename:join(Path, atom_to_list(Module)) ++ ".erl",
|
||||
{ok, File} = file:open(Filename, [write]),
|
||||
Formats = lists:flatten([gen_format(Op)++"\n" || Op <- Ops]),
|
||||
|
||||
io:format(File, "~s", [prelude(" Provide pretty printing functuions for "
|
||||
"Fate instructions.\n")]),
|
||||
io:format(File, "-module(~w).\n\n", [Module]),
|
||||
io:format(File,
|
||||
"-export([format_op/2]).\n\n"
|
||||
"format_arg(t, T) ->\n"
|
||||
" io_lib:format(\"~~p \", [T]);\n"
|
||||
"format_arg(li, List) ->\n"
|
||||
" [[\" \", E] || {immedate, E} <- List];\n"
|
||||
"format_arg(_, {immediate, I}) ->\n"
|
||||
" aeb_fate_data:format(I);\n"
|
||||
"format_arg(a, {arg, N}) -> io_lib:format(\"arg~~p\", [N]);\n"
|
||||
"format_arg(a, {var, N}) -> io_lib:format(\"var~~p\", [N]);\n"
|
||||
"format_arg(a, {stack, 0}) -> \"a\";\n"
|
||||
"format_arg(a, {stack, N}) -> io_lib:format(\"a~~p\", [N]).\n\n"
|
||||
"lookup(Name, Symbols) ->\n"
|
||||
" maps:get(Name, Symbols, Name).\n\n"
|
||||
"~s"
|
||||
, [Formats]),
|
||||
|
||||
io:format(File, "format_op(Op, _Symbols) -> io_lib:format(\";; Bad Op: ~~w\\n\", [Op]).\n", []),
|
||||
file:close(File).
|
||||
|
||||
gen_format(#{opname := Name}) when ('CALL' =:= Name) or (Name =:= 'CALL_T') ->
|
||||
io_lib:format("format_op({~w, {immediate, Function}}, Symbols) ->\n"
|
||||
"[\"~s \", lookup(Function, Symbols)];",
|
||||
[Name, atom_to_list(Name)]);
|
||||
gen_format(#{opname := Name}) when (Name =:= 'CALL_R') or (Name =:= 'CALL_TR') ->
|
||||
io_lib:format("format_op({~w, {immediate, Contract}, {immediate, Function}}, Symbols) ->\n"
|
||||
"[\"~s \", lookup(Contract, Symbols), \".\", lookup(Function, Symbols)];\n"
|
||||
"format_op({~w, Contract, {immediate, Function}}, Symbols) ->\n"
|
||||
"[\"~s \", format_arg(a, Contract), \".\", lookup(Function, Symbols)];",
|
||||
[Name, atom_to_list(Name), Name, atom_to_list(Name)]);
|
||||
gen_format(#{opname := Name, format := atomic}) ->
|
||||
io_lib:format("format_op(~w, _) -> [\"~s\"];", [Name, atom_to_list(Name)]);
|
||||
gen_format(#{opname := Name, format := Args}) ->
|
||||
NameAsString = atom_to_list(Name),
|
||||
case Args of
|
||||
[T0] ->
|
||||
io_lib:format(
|
||||
"format_op({~w, Arg0}, _) ->\n"
|
||||
" [\"~s \", format_arg(~w, Arg0)];",
|
||||
[Name, NameAsString, T0]);
|
||||
[T0, T1] ->
|
||||
io_lib:format(
|
||||
"format_op({~w, Arg0, Arg1}, _) ->\n"
|
||||
" [\"~s \", format_arg(~w, Arg0), "
|
||||
"\" \", format_arg(~w, Arg1)];",
|
||||
[Name, NameAsString, T0, T1]);
|
||||
[T0, T1, T2] ->
|
||||
io_lib:format(
|
||||
"format_op({~w, Arg0, Arg1, Arg2}, _) ->\n"
|
||||
" [\"~s \", format_arg(~w, Arg0), "
|
||||
"\" \", format_arg(~w, Arg1),"
|
||||
"\" \", format_arg(~w, Arg2)];",
|
||||
[Name, NameAsString, T0, T1, T2]);
|
||||
[T0, T1, T2, T3] ->
|
||||
io_lib:format(
|
||||
"format_op({~w, Arg0, Arg1, Arg2, Arg3}, _) ->\n"
|
||||
" [\"~s \", format_arg(~w, Arg0), "
|
||||
"\" \", format_arg(~w, Arg1),"
|
||||
"\" \", format_arg(~w, Arg2),"
|
||||
"\" \", format_arg(~w, Arg3)];",
|
||||
[Name, NameAsString, T0, T1, T2, T3]);
|
||||
[T0, T1, T2, T3, T4] ->
|
||||
io_lib:format(
|
||||
"format_op({~w, Arg0, Arg1, Arg2, Arg3, Arg4}, _) ->\n"
|
||||
" [\"~s \", format_arg(~w, Arg0), "
|
||||
"\" \", format_arg(~w, Arg1),"
|
||||
"\" \", format_arg(~w, Arg2),"
|
||||
"\" \", format_arg(~w, Arg3),"
|
||||
"\" \", format_arg(~w, Arg4)];",
|
||||
[Name, NameAsString, T0, T1, T2, T3, T4]);
|
||||
[T0, T1, T2, T3, T4, T5] ->
|
||||
io_lib:format(
|
||||
"format_op({~w, Arg0, Arg1, Arg2, Arg3, Arg4, Arg5}, _) ->\n"
|
||||
" [\"~s \", format_arg(~w, Arg0), "
|
||||
"\" \", format_arg(~w, Arg1),"
|
||||
"\" \", format_arg(~w, Arg2),"
|
||||
"\" \", format_arg(~w, Arg3),"
|
||||
"\" \", format_arg(~w, Arg4),"
|
||||
"\" \", format_arg(~w, Arg5)];",
|
||||
[Name, NameAsString, T0, T1, T2, T3, T4, T5]);
|
||||
[T0, T1, T2, T3, T4, T5, T6] ->
|
||||
io_lib:format(
|
||||
"format_op({~w, Arg0, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6}, _) ->\n"
|
||||
" [\"~s \", format_arg(~w, Arg0), "
|
||||
"\" \", format_arg(~w, Arg1),"
|
||||
"\" \", format_arg(~w, Arg2),"
|
||||
"\" \", format_arg(~w, Arg3),"
|
||||
"\" \", format_arg(~w, Arg4),"
|
||||
"\" \", format_arg(~w, Arg5),"
|
||||
"\" \", format_arg(~w, Arg6)];",
|
||||
[Name, NameAsString, T0, T1, T2, T3, T4, T5, T6])
|
||||
end.
|
||||
|
@ -50,6 +50,8 @@ sources() ->
|
||||
, "remote"
|
||||
, "test"
|
||||
, "tuple"
|
||||
, "mapofmap"
|
||||
, "immediates"
|
||||
].
|
||||
|
||||
check_roundtrip(File) ->
|
||||
@ -62,4 +64,5 @@ check_roundtrip(File) ->
|
||||
{_Env2, ByteCode2} = assemble(DissasmCode),
|
||||
Code1 = aeb_fate_asm:strip(ByteCode),
|
||||
Code2 = aeb_fate_asm:strip(ByteCode2),
|
||||
io:format("~s~n", [aeb_fate_asm:to_asm(disassemble(ByteCode2))]),
|
||||
?assertEqual(Code1, Code2).
|
||||
|
68
test/asm_code/immediates.fate
Normal file
68
test/asm_code/immediates.fate
Normal file
@ -0,0 +1,68 @@
|
||||
;; CONTRACT immediates
|
||||
|
||||
FUNCTION integer() : integer
|
||||
RETURNR 42
|
||||
|
||||
FUNCTION neg_integer() : integer
|
||||
RETURNR -2374683271468723648732648736498712634876147
|
||||
|
||||
FUNCTION hex_integer() : integer
|
||||
RETURNR 0x0deadbeef0
|
||||
|
||||
FUNCTION bool() : boolean
|
||||
RETURNR true
|
||||
|
||||
FUNCTION bool_f() : boolean
|
||||
RETURNR false
|
||||
|
||||
FUNCTION string() : string
|
||||
RETURNR "Hello"
|
||||
|
||||
FUNCTION map() : {map, integer, boolean}
|
||||
RETURNR {}
|
||||
|
||||
FUNCTION map2() : {map, integer, boolean}
|
||||
RETURNR {1 => true}
|
||||
|
||||
FUNCTION map3() : {map, integer, boolean}
|
||||
RETURNR {1 => true,
|
||||
2 => false}
|
||||
|
||||
FUNCTION map4() : {map, integer, {map, string, boolean}}
|
||||
RETURNR {1 => { "foo" => true, "bar" => false},
|
||||
2 => {},
|
||||
3 => { "foo" => false}}
|
||||
|
||||
FUNCTION nil() : {list, integer}
|
||||
RETURNR []
|
||||
|
||||
FUNCTION list1() : {list, integer}
|
||||
RETURNR [1]
|
||||
|
||||
FUNCTION list2() : {list, integer}
|
||||
RETURNR [1, 2]
|
||||
|
||||
|
||||
FUNCTION no_bits() : bits
|
||||
RETURNR <>
|
||||
|
||||
FUNCTION all_bits() : bits
|
||||
RETURNR !<>
|
||||
|
||||
FUNCTION some_bits() : bits
|
||||
RETURNR <101010>
|
||||
|
||||
FUNCTION many_bits() : bits
|
||||
RETURNR !<010101>
|
||||
|
||||
FUNCTION group_bits() : bits
|
||||
RETURNR <1010 1010 0011 1001>
|
||||
|
||||
FUNCTION unit() : {tuple, []}
|
||||
RETURNR ()
|
||||
|
||||
FUNCTION tuple() : {tuple, [integer, boolean, string, {tuple, [integer, integer]}]}
|
||||
RETURNR (42, true, "FooBar", (1, 2))
|
||||
|
||||
|
||||
|
7
test/asm_code/mapofmap.fate
Normal file
7
test/asm_code/mapofmap.fate
Normal file
@ -0,0 +1,7 @@
|
||||
;; CONTRACT mapofmap
|
||||
FUNCTION map() : {map, integer, {map, string, boolean}}
|
||||
RETURNR {1 => { "foo" => true, "bar" => false},
|
||||
2 => {},
|
||||
3 => { "foo" => false}}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user