Generate code for fate ops from spec.
This commit is contained in:
parent
01ae99f7e8
commit
c85af9e7f3
@ -10,10 +10,15 @@
|
|||||||
%%% DUP
|
%%% DUP
|
||||||
%%% Identifiers start with a lower case letter
|
%%% Identifiers start with a lower case letter
|
||||||
%%% an_identifier
|
%%% an_identifier
|
||||||
%%% References to function arguments start with arg
|
%%% References to function arguments start with arg followed by an integer
|
||||||
%%% arg0
|
%%% arg0
|
||||||
%%% References to variables/registers start with var
|
%%% References to variables/registers start with var followed by an integer
|
||||||
%%% var0
|
%%% var0
|
||||||
|
%%% References to stack postions is either a (for stack 0)
|
||||||
|
%%% or start with stack followed by an integer
|
||||||
|
%%% stack1
|
||||||
|
%%% a
|
||||||
|
%%%
|
||||||
%%% Immediates can be of 9 types:
|
%%% Immediates can be of 9 types:
|
||||||
%%% 1. Integers
|
%%% 1. Integers
|
||||||
%%% 42
|
%%% 42
|
||||||
@ -815,7 +820,7 @@ to_list_of_types(Tokens) ->
|
|||||||
{[Type], Rest}
|
{[Type], Rest}
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
-spec serialize_type(aeb_fate_date:fate_type_type()) -> [byte()].
|
||||||
serialize_type(integer) -> [0];
|
serialize_type(integer) -> [0];
|
||||||
serialize_type(boolean) -> [1];
|
serialize_type(boolean) -> [1];
|
||||||
serialize_type({list, T}) -> [2 | serialize_type(T)];
|
serialize_type({list, T}) -> [2 | serialize_type(T)];
|
||||||
|
@ -1,5 +1,76 @@
|
|||||||
|
%% Provide constructor functuions for Fate instructions.
|
||||||
|
%% Provide types and documentation for Fate instructions.
|
||||||
|
|
||||||
|
|
||||||
-module(aeb_fate_code).
|
-module(aeb_fate_code).
|
||||||
|
|
||||||
|
-include_lib("aebytecode/include/aeb_fate_data.hrl").
|
||||||
|
|
||||||
|
-type fate_arg_immediate(T) :: {immediate, T}.
|
||||||
|
-type fate_arg_var() :: {var, integer()}.
|
||||||
|
-type fate_arg_arg() :: {arg, integer()}.
|
||||||
|
-type fate_arg_stack() :: {stack, integer()}.
|
||||||
|
-type fate_arg() :: fate_arg_immediate()
|
||||||
|
| fate_arg_var()
|
||||||
|
| fate_arg_arg()
|
||||||
|
| fate_arg_stack().
|
||||||
|
|
||||||
|
-type fate_arg_immediate() :: {immediate, aeb_fate_data:fate_type()}.
|
||||||
|
|
||||||
|
-type fate_return() :: 'RETURN'.
|
||||||
|
-type fate_returnr() :: {'RETURNR', fate_arg()}.
|
||||||
|
-type fate_call() :: {'CALL',
|
||||||
|
fate_arg_immediate(aeb_fate_data:fate_string())}.
|
||||||
|
-type fate_call_t() :: {'CALL_T',
|
||||||
|
fate_arg_immediate(aeb_fate_data:fate_string())}.
|
||||||
|
-type fate_call_r() :: {'CALL_R', fate_arg(),
|
||||||
|
fate_arg_immediate(aeb_fate_data:fate_string())}.
|
||||||
|
-type fate_call_tr() :: {'CALL_TR', fate_arg(),
|
||||||
|
fate_arg_immediate(aeb_fate_data:fate_string())}.
|
||||||
|
-type fate_jump() :: {'JUMP',
|
||||||
|
fate_arg_immediate(aeb_fate_data:fate_integer())}.
|
||||||
|
-type fate_jumpif() :: {'JUMPIF', fate_arg(),
|
||||||
|
fate_arg_immediate(aeb_fate_data:fate_integer())}.
|
||||||
|
-type fate_switch_v2() :: {'SWITCH_V2', fate_arg(),
|
||||||
|
fate_arg_immediate(aeb_fate_data:fate_integer()),
|
||||||
|
fate_arg_immediate(aeb_fate_data:fate_integer())}.
|
||||||
|
-type fate_switch_v3() :: {'SWITCH_V3', fate_arg(),
|
||||||
|
fate_arg_immediate(aeb_fate_data:fate_integer()),
|
||||||
|
fate_arg_immediate(aeb_fate_data:fate_integer()),
|
||||||
|
fate_arg_immediate(aeb_fate_data:fate_integer())}.
|
||||||
|
-type fate_switch_vn() :: {'SWITCH_VN', fate_arg(),
|
||||||
|
fate_arg_immediate(aeb_fate_data:fate_integer()),
|
||||||
|
[fate_arg_immediate(aeb_fate_data:fate_integer())]}.
|
||||||
|
-type fate_push() :: {'PUSH', fate_arg()}.
|
||||||
|
-type fate_inca() :: 'INCA'.
|
||||||
|
-type fate_inc() :: {'INC', fate_arg()}.
|
||||||
|
-type fate_deca() :: 'DECA'.
|
||||||
|
-type fate_dec() :: {'DEC', fate_arg()}.
|
||||||
|
|
||||||
|
|
||||||
|
-type fate_code() :: fate_return()
|
||||||
|
| fate_returnr()
|
||||||
|
| fate_call()
|
||||||
|
| fate_call_t()
|
||||||
|
| fate_call_r()
|
||||||
|
| fate_call_tr()
|
||||||
|
| fate_jump()
|
||||||
|
| fate_jumpif()
|
||||||
|
| fate_switch_v2()
|
||||||
|
| fate_switch_v3()
|
||||||
|
| fate_switch_vn()
|
||||||
|
| fate_push()
|
||||||
|
| fate_inca()
|
||||||
|
| fate_inc()
|
||||||
|
| fate_deca()
|
||||||
|
| fate_dec()
|
||||||
|
.
|
||||||
|
|
||||||
|
-export_type([ fate_code/0
|
||||||
|
|
||||||
|
, fate_arg/0
|
||||||
|
]).
|
||||||
|
|
||||||
-export([ return/0
|
-export([ return/0
|
||||||
, return/1
|
, return/1
|
||||||
, call/1
|
, call/1
|
||||||
@ -10,8 +81,7 @@
|
|||||||
, jumpif/2
|
, jumpif/2
|
||||||
, switch/3
|
, switch/3
|
||||||
, switch/4
|
, switch/4
|
||||||
, switch/5
|
, switch_n/2
|
||||||
, switch/6
|
|
||||||
, push/1
|
, push/1
|
||||||
, inc/0
|
, inc/0
|
||||||
, inc/1
|
, inc/1
|
||||||
@ -76,64 +146,80 @@
|
|||||||
|
|
||||||
-define(i(__X__), {immediate, __X__ }).
|
-define(i(__X__), {immediate, __X__ }).
|
||||||
|
|
||||||
|
-spec return() -> fate_return().
|
||||||
return() ->
|
return() ->
|
||||||
'RETURN'.
|
'RETURN'.
|
||||||
|
|
||||||
|
-spec return(fate_arg()) -> fate_returnr().
|
||||||
return(Arg) ->
|
return(Arg) ->
|
||||||
{'RETURNR', Arg}.
|
{'RETURNR', Arg}.
|
||||||
|
|
||||||
call(Function) when is_binary(Function)->
|
-spec call(aeb_fate_data:fate_string()) -> fate_call().
|
||||||
|
call(Function) when ?IS_FATE_STRING(Function)->
|
||||||
{'CALL', ?i(Function) }.
|
{'CALL', ?i(Function) }.
|
||||||
|
|
||||||
call_t(Function) when is_binary(Function) ->
|
-spec call_t(aeb_fate_data:fate_string()) -> fate_call_t().
|
||||||
|
call_t(Function) when ?IS_FATE_STRING(Function) ->
|
||||||
{'CALL_T', ?i(Function)}.
|
{'CALL_T', ?i(Function)}.
|
||||||
|
|
||||||
call_r(Contract, Function) when is_binary(Function) ->
|
-spec call_r(fate_arg(), aeb_fate_data:fate_string()) -> fate_call_r().
|
||||||
|
call_r(Contract, Function) when ?IS_FATE_STRING(Function) ->
|
||||||
{'CALL_R', Contract, ?i(Function)}.
|
{'CALL_R', Contract, ?i(Function)}.
|
||||||
|
|
||||||
call_tr(Contract, Function) when is_binary(Function) ->
|
-spec call_tr(fate_arg(), aeb_fate_data:fate_string()) -> fate_call_tr().
|
||||||
|
call_tr(Contract, Function) when ?IS_FATE_STRING(Function) ->
|
||||||
{'CALL_TR', Contract, ?i(Function)}.
|
{'CALL_TR', Contract, ?i(Function)}.
|
||||||
|
|
||||||
jump(BB) when is_integer(BB) ->
|
-spec jump(aeb_fate_data:fate_integer()) -> fate_jump().
|
||||||
|
jump(BB) when ?IS_FATE_INTEGER(BB) ->
|
||||||
{'JUMP', ?i(BB)}.
|
{'JUMP', ?i(BB)}.
|
||||||
|
|
||||||
jumpif(Arg, BB) when is_integer(BB) ->
|
-spec jumpif(fate_arg(), aeb_fate_data:fate_integer()) -> fate_jumpif().
|
||||||
|
jumpif(Arg, BB) when ?IS_FATE_INTEGER(BB) ->
|
||||||
{'JUMPIF', Arg, ?i(BB)}.
|
{'JUMPIF', Arg, ?i(BB)}.
|
||||||
|
|
||||||
switch(Arg, BB1, BB2) when is_integer(BB1),
|
-spec switch(fate_arg(),
|
||||||
is_integer(BB2) ->
|
aeb_fate_data:fate_integer(),
|
||||||
|
aeb_fate_data:fate_integer())
|
||||||
|
-> fate_switch_v2().
|
||||||
|
switch(Arg, BB1, BB2) when ?IS_FATE_INTEGER(BB1),
|
||||||
|
?IS_FATE_INTEGER(BB2) ->
|
||||||
{'SWITCH_V2', Arg, ?i(BB1), ?i(BB2)}.
|
{'SWITCH_V2', Arg, ?i(BB1), ?i(BB2)}.
|
||||||
|
|
||||||
switch(Arg, BB1, BB2, BB3) when is_integer(BB1),
|
-spec switch(fate_arg(),
|
||||||
is_integer(BB2),
|
aeb_fate_data:fate_integer(),
|
||||||
is_integer(BB3) ->
|
aeb_fate_data:fate_integer(),
|
||||||
|
aeb_fate_data:fate_integer())
|
||||||
|
-> fate_switch_v3().
|
||||||
|
switch(Arg, BB1, BB2, BB3) when ?IS_FATE_INTEGER(BB1),
|
||||||
|
?IS_FATE_INTEGER(BB2),
|
||||||
|
?IS_FATE_INTEGER(BB3) ->
|
||||||
{'SWITCH_V3', Arg, ?i(BB1), ?i(BB2), ?i(BB3)}.
|
{'SWITCH_V3', Arg, ?i(BB1), ?i(BB2), ?i(BB3)}.
|
||||||
|
|
||||||
switch(Arg, BB1, BB2, BB3, BB4) when is_integer(BB1),
|
-spec switch_n(fate_arg(),
|
||||||
is_integer(BB2),
|
[aeb_fate_data:fate_integer()])
|
||||||
is_integer(BB3),
|
-> fate_switch_vn().
|
||||||
is_integer(BB4) ->
|
switch_n(Arg, BBS) when is_list(BBS) ->
|
||||||
{'SWITCH_V4', Arg, ?i(BB1), ?i(BB2), ?i(BB3), ?i(BB4)}.
|
N = length(BBS),
|
||||||
|
{'SWITCH_VN', Arg, ?i(N), [?i(BB) || BB <- BBS]}.
|
||||||
switch(Arg, BB1, BB2, BB3, BB4, BB5) when is_integer(BB1),
|
|
||||||
is_integer(BB2),
|
|
||||||
is_integer(BB3),
|
|
||||||
is_integer(BB4),
|
|
||||||
is_integer(BB5) ->
|
|
||||||
{'SWITCH_V5', Arg, ?i(BB1), ?i(BB2), ?i(BB3), ?i(BB4), ?i(BB5)}.
|
|
||||||
|
|
||||||
|
-spec push(fate_arg()) -> fate_push().
|
||||||
push(Arg) ->
|
push(Arg) ->
|
||||||
{'PUSH', Arg}.
|
{'PUSH', Arg}.
|
||||||
|
|
||||||
|
-spec inc() -> fate_inca().
|
||||||
inc() ->
|
inc() ->
|
||||||
'INCA'.
|
'INCA'.
|
||||||
|
|
||||||
|
-spec inc(fate_arg()) -> fate_inc().
|
||||||
inc(Arg) ->
|
inc(Arg) ->
|
||||||
{'INC', Arg}.
|
{'INC', Arg}.
|
||||||
|
|
||||||
|
-spec dec() -> fate_deca().
|
||||||
dec() ->
|
dec() ->
|
||||||
'DECA'.
|
'DECA'.
|
||||||
|
|
||||||
|
-spec dec(fate_arg()) -> fate_dec().
|
||||||
dec(Arg) ->
|
dec(Arg) ->
|
||||||
{'DEC', Arg}.
|
{'DEC', Arg}.
|
||||||
|
|
||||||
@ -182,7 +268,7 @@ or_op(Dest, Left, Right) ->
|
|||||||
not_op(Dest, Arg) ->
|
not_op(Dest, Arg) ->
|
||||||
{'NOT', Dest, Arg}.
|
{'NOT', Dest, Arg}.
|
||||||
|
|
||||||
tuple(Size) when is_integer(Size) ->
|
tuple(Size) when ?IS_FATE_INTEGER(Size) ->
|
||||||
{'TUPLE', ?i(Size)}.
|
{'TUPLE', ?i(Size)}.
|
||||||
|
|
||||||
element_op(Type, Dest, N, T) ->
|
element_op(Type, Dest, N, T) ->
|
||||||
@ -290,7 +376,7 @@ bits_diff(To, Bits, Bit) ->
|
|||||||
dup() ->
|
dup() ->
|
||||||
'DUPA'.
|
'DUPA'.
|
||||||
|
|
||||||
dup(N) when is_integer(N) ->
|
dup(N) when ?IS_FATE_INTEGER(N) ->
|
||||||
{'DUP', ?i(N)}.
|
{'DUP', ?i(N)}.
|
||||||
|
|
||||||
pop() ->
|
pop() ->
|
||||||
|
@ -15,10 +15,18 @@
|
|||||||
|
|
||||||
-type fate_variant() :: ?FATE_VARIANT_T.
|
-type fate_variant() :: ?FATE_VARIANT_T.
|
||||||
|
|
||||||
-type fate_void() :: ?FATE_VOID_T.
|
|
||||||
|
|
||||||
-type fate_tuple() :: ?FATE_TUPLE_T.
|
-type fate_tuple() :: ?FATE_TUPLE_T.
|
||||||
|
|
||||||
|
-type fate_type_type() :: integer
|
||||||
|
| boolean
|
||||||
|
| {list, fate_type()}
|
||||||
|
| {map, fate_type(), fate_type()}
|
||||||
|
| {tuple, [fate_type()]}
|
||||||
|
| address
|
||||||
|
| bits
|
||||||
|
| {variant, integer()}.
|
||||||
|
|
||||||
|
|
||||||
-type fate_type() ::
|
-type fate_type() ::
|
||||||
fate_boolean()
|
fate_boolean()
|
||||||
| fate_integer()
|
| fate_integer()
|
||||||
@ -30,11 +38,21 @@
|
|||||||
| fate_address()
|
| fate_address()
|
||||||
| fate_variant()
|
| fate_variant()
|
||||||
| fate_map()
|
| fate_map()
|
||||||
| fate_list()
|
| fate_type_type().
|
||||||
| fate_tuple()
|
|
||||||
| fate_void(). %% Not sure we need this.
|
|
||||||
|
|
||||||
-export_type([fate_type/0]).
|
-export_type([fate_type/0
|
||||||
|
, fate_boolean/0
|
||||||
|
, fate_integer/0
|
||||||
|
, fate_nil/0
|
||||||
|
, fate_list/0
|
||||||
|
, fate_unit/0
|
||||||
|
, fate_tuple/0
|
||||||
|
, fate_string/0
|
||||||
|
, fate_address/0
|
||||||
|
, fate_variant/0
|
||||||
|
, fate_map/0
|
||||||
|
, fate_type_type/0
|
||||||
|
]).
|
||||||
|
|
||||||
-export([ make_integer/1
|
-export([ make_integer/1
|
||||||
, make_boolean/1
|
, make_boolean/1
|
||||||
@ -111,7 +129,6 @@ decode(M) when ?IS_FATE_MAP(M) ->
|
|||||||
|
|
||||||
-spec format(fate_type()) -> iolist().
|
-spec format(fate_type()) -> iolist().
|
||||||
format(I) when ?IS_FATE_INTEGER(I) -> integer_to_list(?MAKE_FATE_INTEGER(I));
|
format(I) when ?IS_FATE_INTEGER(I) -> integer_to_list(?MAKE_FATE_INTEGER(I));
|
||||||
format(?FATE_VOID) -> "void";
|
|
||||||
format(?FATE_TRUE) -> "true";
|
format(?FATE_TRUE) -> "true";
|
||||||
format(?FATE_FALSE) -> "false";
|
format(?FATE_FALSE) -> "false";
|
||||||
format(?FATE_NIL) -> "[]";
|
format(?FATE_NIL) -> "[]";
|
||||||
|
329
src/aeb_fate_generate_ops.erl
Normal file
329
src/aeb_fate_generate_ops.erl
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
|
||||||
|
|
||||||
|
-module(aeb_fate_generate_ops).
|
||||||
|
|
||||||
|
-export([generate/0]).
|
||||||
|
|
||||||
|
-define(ati(__X__), {immediate, __X__}).
|
||||||
|
-define(atv(__X__), {var, __X__}).
|
||||||
|
-define(ata(__X__), {arg, __X__}).
|
||||||
|
-define(ats(__X__), {stack, __X__}).
|
||||||
|
|
||||||
|
-define(ta(), "fate_arg()").
|
||||||
|
-define(ti(__X__), "fate_arg_immediate(" __X__ ")").
|
||||||
|
-define(ts, "aeb_fate_data:fate_string()").
|
||||||
|
|
||||||
|
generate() ->
|
||||||
|
Ops = gen(ops_defs()),
|
||||||
|
io:format("ops: ~p\n", [Ops]),
|
||||||
|
HrlFile = "aeb_new_fate_opcodes.hrl",
|
||||||
|
generate_header_file(HrlFile, Ops),
|
||||||
|
generate_opcodes_ops(aeb_new_fate_opcodes, HrlFile, Ops),
|
||||||
|
generate_code_ops(aeb_new_fate_code, Ops).
|
||||||
|
|
||||||
|
ops_defs() ->
|
||||||
|
%% Opname, Opcode, args, end_bb, gas, format, Constructor, Documentation
|
||||||
|
[ { 'NOP', 16#00, 0, false, 1, atomic, nop, "The no op. does nothing."}
|
||||||
|
, { 'RETURN', 16#01, 0, true, 2, atomic, return, "Return from function call pop stack to arg0."}
|
||||||
|
, { 'RETURNR', 16#68, 1, true, 2, [a], returnr, "Return from function call pop stack to arg0."}
|
||||||
|
, { 'CALL', 16#02, 1, true, 4, [is], call, "Call given function with args on stack."}
|
||||||
|
, { 'CALL_T', 16#04, 1, true, 4, [is], call_t, "Tail call to given function."}
|
||||||
|
, { 'CALL_R', 16#03, 2, true, 8, [a, is], call_r, "Remote call to given contract and function."}
|
||||||
|
, { 'CALL_TR', 16#05, 2, true, 8, [a, is], call_tr, "Remote tail call to given contract and function."}
|
||||||
|
, { 'JUMP', 16#06, 1, true, 3, [ii], jump, "Jump to a basic block."}
|
||||||
|
, { 'JUMPIF', 16#07, 2, true, 4, [a, ii], jumpif, "Conditional jump to a basic block."}
|
||||||
|
, { 'SWITCH_V2',16#6a, 3, true, 4, [a, ii, ii], switch, "Conditional jump to a basic block on variant tag."}
|
||||||
|
, { 'SWITCH_V3',16#6b, 4, true, 4, [a, ii, ii, ii], switch,"Conditional jump to a basic block on variant tag."}
|
||||||
|
, { 'SWITCH_VN',16#6c, 2, true, 4, [a, li], switch,"Conditional jump to a basic block on variant tag."}
|
||||||
|
, { 'PUSH', 16#09, 1, false, 2, [a], push, "Push argument to stack."}
|
||||||
|
, { 'INCA', 16#71, 0, false, 2, atomic, inc, "Increment accumulator."}
|
||||||
|
, { 'INC', 16#53, 1, false, 2, [a], inc, "Increment argument."}
|
||||||
|
, { 'DECA', 16#72, 0, false, 2, atomic, dec, "Decrement accumulator."}
|
||||||
|
, { 'DEC', 16#54, 1, false, 2, [a], dec, "Decrement argument."}
|
||||||
|
, { 'ADD', 16#11, 3, false, 3, [a,a,a], add, "Arg0 := Arg1 + Arg2."}
|
||||||
|
, { 'SUB', 16#13, 3, false, 3, [a,a,a], sub, "Arg0 := Arg1 - Arg2."}
|
||||||
|
, { 'MUL', 16#12, 3, false, 3, [a,a,a], mul, "Arg0 := Arg1 * Arg2."}
|
||||||
|
, { 'DIV', 16#14, 3, false, 3, [a,a,a], divide, "Arg0 := Arg1 / Arg2."}
|
||||||
|
, { 'MOD', 16#15, 3, false, 3, [a,a,a], modulo, "Arg0 := Arg1 mod Arg2."}
|
||||||
|
, { 'POW', 16#16, 3, false, 3, [a,a,a], pow, "Arg0 := Arg1 ^ Arg2."}
|
||||||
|
, { 'LT', 16#17, 3, false, 3, [a,a,a], lt, "Arg0 := Arg1 < Arg2."}
|
||||||
|
, { 'GT', 16#18, 3, false, 3, [a,a,a], gt, "Arg0 := Arg1 > Arg2."}
|
||||||
|
, { 'EQ', 16#19, 3, false, 3, [a,a,a], eq, "Arg0 := Arg1 = Arg2."}
|
||||||
|
, { 'ELT', 16#1a, 3, false, 3, [a,a,a], elt, "Arg0 := Arg1 =< Arg2."}
|
||||||
|
, { 'EGT', 16#1b, 3, false, 3, [a,a,a], egt, "Arg0 := Arg1 >= Arg2."}
|
||||||
|
, { 'NEQ', 16#1c, 3, false, 3, [a,a,a], neq, "Arg0 := Arg1 /= Arg2."}
|
||||||
|
, { 'AND', 16#1d, 3, false, 3, [a,a,a], and_op, "Arg0 := Arg1 and Arg2."}
|
||||||
|
, { 'OR', 16#1e, 3, false, 3, [a,a,a], or_op, "Arg0 := Arg1 or Arg2."}
|
||||||
|
, { 'NOT', 16#1f, 2, false, 3, [a,a], not_op, "Arg0 := not Arg1."}
|
||||||
|
, { 'TUPLE', 16#20, 1, false, 3, [ii], tuple, "Create a tuple of size = Arg0. Elements on stack."}
|
||||||
|
, { 'ELEMET', 16#21, 4, false, 3, [t,a,a,a], element_op, "Arg1 := element(Arg2, Arg3). The element should be of type Arg1"}
|
||||||
|
, { 'MAP_EMPTY',16#22, 1, false, 3, [a], map_empty, "Arg0 := #{}."}
|
||||||
|
, { 'MAP_LOOKUP',16#23, 3, false, 3, [a, a, a], map_lookup, "Arg0 := lookup key Arg2 in map Arg1."}
|
||||||
|
, { 'MAP_LOOKUPD',16#69, 4, false, 3, [a, a, a, a], map_lookup, "Arg0 := lookup key Arg2 in map Arg1 if key exists in map otherwise Arg0 := Arg3."}
|
||||||
|
, { 'MAP_UPDATE',16#24, 4, false, 3, [a, a, a, a], map_update, "Arg0 := update key Arg2 in map Arg1 with value Arg3."}
|
||||||
|
, { 'MAP_DELETE',16#25, 3, false, 3, [a, a, a], map_delete, "Arg0 := delete key Arg2 from map Arg1."}
|
||||||
|
, { 'MAP_MEMBER',16#26, 3, false, 3, [a, a, a], map_member, "Arg0 := true if key Arg2 is in map Arg1."}
|
||||||
|
, { 'NIL', 16#28, 1, false, 3, [a], nil, "Arg0 := []."}
|
||||||
|
, { 'IS_NIL', 16#29, 2, false, 3, [a, a], is_nil, "Arg0 := true if Arg1 == []."}
|
||||||
|
, {'CONS', 16#2a, 3, false, 3, [a, a, a], cons, "Arg0 := [Arg1|Arg2]."}
|
||||||
|
, {'HD', 16#2b, 2, false, 3, [a, a], hd, "Arg0 := head of list Arg1."}
|
||||||
|
, {'TL', 16#2c, 2, false, 3, [a, a], tl, "Arg0 := tail of list Arg1."}
|
||||||
|
, {'LENGTH', 16#2d, 2, false, 3, [a, a], length, "Arg0 := length of list Arg1."}
|
||||||
|
|
||||||
|
, {'STR_EQ', 16#2e, 3, false, 3, [a, a, a], str_eq, "Arg0 := true iff the strings Arg1 and Arg2 are the same."}
|
||||||
|
, {'STR_JOIN', 16#2f, 3, false, 3, [a, a, a], str_join, "Arg0 := string Arg1 followed by string Arg2."}
|
||||||
|
, {'INT_TO_STR', 16#55, 2, false, 3, [a, a], int_to_str, "Arg0 := turn integer Arg1 into a string."}
|
||||||
|
, {'ADDR_TO_STR', 16#30, 2, false, 3, [a, a], addr_to_str, "Arg0 := turn address Arg1 into a string."}
|
||||||
|
, {'STR_REVERSE', 16#31, 2, false, 3, [a, a], str_reverse, "Arg0 := the reverse of string Arg1."}
|
||||||
|
, {'INT_TO_ADDR', 16#32, 2, false, 3, [a, a], int_to_addr, "Arg0 := turn integer Arg1 into an address."}
|
||||||
|
, {'VARIANT', 16#33, 4, false, 3, [a, a, a, a], variant, "Arg0 := create a variant of size Arg1 with the tag Arg2 (Arg2 < Arg1) and take Arg3 elements from the stack."}
|
||||||
|
, {'VARIANT_TEST', 16#34,3, false, 3, [a, a, a], variant_test,"Arg0 := true if variant Arg1 has the tag Arg2."}
|
||||||
|
, {'VARIANT_ELEMENT',16#35,3,false, 3, [a, a, a], variant_element,"Arg0 := element number Arg2 from variant Arg1."}
|
||||||
|
, {'BITS_NONEA', 16#6e, 0, false, 3, atomic, bits_none, "accumulator := empty bitmap."}
|
||||||
|
, {'BITS_NONE', 16#36, 1, false, 3, [a], bits_none, "Arg0 := empty bitmap."}
|
||||||
|
, {'BITS_ALLA', 16#6f, 0, false, 3, atomic, bits_all, "accumulator := full bitmap."}
|
||||||
|
, {'BITS_ALL', 16#37, 1, false, 3, [a], bits_all, "Arg0 := full bitmap."}
|
||||||
|
, {'BITS_ALL_N', 16#6d, 2, false, 3, [a, a], bits_all_n, "Arg0 := bitmap with Arg1 bits set."}
|
||||||
|
, {'BITS_SET', 16#38, 3, false, 3, [a, a, a], bits_set, "Arg0 := set bit Arg2 of bitmap Arg1."}
|
||||||
|
, {'BITS_CLEAR',16#39, 3, false, 3, [a, a, a], bits_clear, "Arg0 := clear bit Arg2 of bitmap Arg1."}
|
||||||
|
, {'BITS_TEST', 16#3a, 3, false, 3, [a, a, a], bits_test, "Arg0 := true if bit Arg2 of bitmap Arg1 is set."} , {'BITS_SUM', 16#3b, 2, false, 3, [a, a], bits_sum, "Arg0 := sum of set bits in bitmap Arg1. Exception if infinit bitmap."}
|
||||||
|
, {'BITS_OR', 16#3c, 3, false, 3, [a, a, a], bits_or, "Arg0 := Arg1 v Arg2."}
|
||||||
|
, {'BITS_AND', 16#3d, 3, false, 3, [a, a, a], bits_and, "Arg0 := Arg1 ^ Arg2."}
|
||||||
|
, {'BITS_DIFF', 16#3e, 3, false, 3, [a, a, a], bits_diff, "Arg0 := Arg1 - Arg2."}
|
||||||
|
, {'DUPA', 16#70, 0, false, 3, atomic, dup, "push copy of accumulator on stack."}
|
||||||
|
, {'DUP', 16#0a, 1, false, 3, [a], dup, "push Arg0 stack pos on top of stack."}
|
||||||
|
, {'POP', 16#0b, 1, false, 3, [a], pop, "Arg0 := top of stack."}
|
||||||
|
, {'STORE', 16#10, 2, false, 3, [a, a], store, "Arg0 := Arg1."}
|
||||||
|
].
|
||||||
|
|
||||||
|
|
||||||
|
generate_header_file(Filename, Ops) ->
|
||||||
|
{ok, File} = file:open(Filename, [write]),
|
||||||
|
Defines = lists:flatten([gen_defines(Op) || Op <- Ops]),
|
||||||
|
io:format(File, "~s", [prelude("Provides opcode defines.\n")]),
|
||||||
|
io:format(File, "%% FATE opcodes\n~s", [Defines]),
|
||||||
|
file:close(File).
|
||||||
|
|
||||||
|
generate_opcodes_ops(Modulename, HrlFile, Ops) ->
|
||||||
|
Filename = atom_to_list(Modulename) ++ ".erl",
|
||||||
|
|
||||||
|
{ok, File} = file:open(Filename, [write]),
|
||||||
|
Mnemonic = lists:flatten([gen_mnemonic(Op) || Op <- Ops]),
|
||||||
|
ToOp = lists:flatten([gen_m_to_op(Op) || Op <- Ops]),
|
||||||
|
Args = lists:flatten([gen_args(Op) || Op <- Ops]),
|
||||||
|
EndBB = lists:flatten([gen_bb(Op) || Op <- Ops]),
|
||||||
|
|
||||||
|
io:format(File, "~s", [prelude("Provides opcode primitives.\n")]),
|
||||||
|
io:format(File, "~s", [ops_exports(Modulename, HrlFile,
|
||||||
|
["args/1\n"
|
||||||
|
" , end_bb/1\n"
|
||||||
|
" , mnemonic/1\n"
|
||||||
|
" , m_to_op/1\n"
|
||||||
|
])]),
|
||||||
|
|
||||||
|
io:format(File, "%% FATE mnemonics\n~s", [Mnemonic]),
|
||||||
|
io:format(File, "mnemonic(Op) -> exit({bad_opcode, Op}).\n\n", []),
|
||||||
|
|
||||||
|
io:format(File, "%% FATE opcodes\n~s", [ToOp]),
|
||||||
|
io:format(File, "m_to_op(M) -> exit({bad_mnemonic, M}).\n\n", []),
|
||||||
|
|
||||||
|
io:format(File, "%% FATE numbers of args to op.\n~s", [Args]),
|
||||||
|
io:format(File, "args(Op) -> exit({bad_opcode, Op}).\n\n", []),
|
||||||
|
|
||||||
|
io:format(File, "%% Does FATE Op end a Basic Block?\n~s", [EndBB]),
|
||||||
|
io:format(File, "end_bb(_) -> false.\n\n", []),
|
||||||
|
|
||||||
|
file:close(File).
|
||||||
|
|
||||||
|
generate_code_ops(Modulename, Ops) ->
|
||||||
|
Filename = atom_to_list(Modulename) ++ ".erl",
|
||||||
|
|
||||||
|
{ok, File} = file:open(Filename, [write]),
|
||||||
|
Types = lists:flatten([gen_type(Op) || Op <- Ops]),
|
||||||
|
TypeExports = lists:flatten([gen_type_exports(Op) || Op <- Ops]),
|
||||||
|
[#{type_name := FirstType} | RestOfOps] = Ops,
|
||||||
|
FateTypes = lists:flatten([gen_fate_code_type(Op) || Op <- RestOfOps]),
|
||||||
|
ConstructorExports = lists:flatten([gen_constructor_exports(Op) || Op <- Ops]),
|
||||||
|
Constructors = lists:flatten([gen_constructors(Op) || Op <- Ops]),
|
||||||
|
|
||||||
|
io:format(File, "~s", [prelude(" Provide constructor functuions for "
|
||||||
|
"Fate instructions.\n%%% Provide types"
|
||||||
|
" and documentation for Fate "
|
||||||
|
"instructions.\n")]),
|
||||||
|
io:format(File, "-module(~w).\n\n", [Modulename]),
|
||||||
|
io:format(File, "-include_lib(\"aebytecode/include/aeb_fate_data.hrl\").\n\n"
|
||||||
|
"-define(i(__X__), {immediate, __X__ }).\n\n"
|
||||||
|
"-type fate_arg_immediate(T) :: {immediate, T}.\n"
|
||||||
|
"-type fate_arg_var() :: {var, integer()}.\n"
|
||||||
|
"-type fate_arg_arg() :: {arg, integer()}.\n"
|
||||||
|
"-type fate_arg_stack() :: {stack, integer()}.\n"
|
||||||
|
"-type fate_arg() :: fate_arg_immediate()\n"
|
||||||
|
" | fate_arg_var()\n"
|
||||||
|
" | fate_arg_arg()\n"
|
||||||
|
" | fate_arg_stack().\n\n"
|
||||||
|
"-type fate_arg_immediate() :: {immediate, aeb_fate_data:fate_type()}.\n"
|
||||||
|
, []),
|
||||||
|
|
||||||
|
io:format(File, "~s", [Types]),
|
||||||
|
io:format(File, "-type fate_code() :: ~s\n~s .\n\n",
|
||||||
|
[FirstType, FateTypes]),
|
||||||
|
io:format(File, "-export_type([ fate_code/0\n~s ]).\n\n", [TypeExports]),
|
||||||
|
io:format(File, "-export([ foo/0\n~s ]).\n\n", [ConstructorExports]),
|
||||||
|
io:format(File, "~s\n", [Constructors]),
|
||||||
|
|
||||||
|
io:format(File, "foo() -> \"A temp hack.\".\n", []),
|
||||||
|
|
||||||
|
|
||||||
|
file:close(File).
|
||||||
|
|
||||||
|
gen_type(#{type_name := TypeName, type := Type}) ->
|
||||||
|
lists:flatten(io_lib:format("-type ~-25s :: ~s.\n",
|
||||||
|
[TypeName, Type])).
|
||||||
|
|
||||||
|
gen_fate_code_type(#{type_name := TypeName}) ->
|
||||||
|
lists:flatten(io_lib:format(" | ~s\n", [TypeName])).
|
||||||
|
|
||||||
|
gen_type_exports(#{type_name := TypeName}) ->
|
||||||
|
lists:flatten(io_lib:format(" , ~s/0\n", [TypeName--"()"])).
|
||||||
|
|
||||||
|
gen_constructor_exports(#{constructor_type := Function}) ->
|
||||||
|
lists:flatten(io_lib:format(" , ~s\n", [Function])).
|
||||||
|
|
||||||
|
gen_constructors(#{constructor := Function, format := atomic,
|
||||||
|
type_name := Type, opname := Name}) ->
|
||||||
|
lists:flatten(io_lib:format("-spec ~s() -> ~s.\n"
|
||||||
|
"~s() ->\n"
|
||||||
|
" ~w.\n\n",
|
||||||
|
[Function, Type, Function, Name]));
|
||||||
|
gen_constructors(#{constructor := Function, format := ArgSpec,
|
||||||
|
type_name := Type, opname := Name}) ->
|
||||||
|
ArgTypeSpecs = gen_arg_type_specs(ArgSpec),
|
||||||
|
Args = gen_arg_names(0, ArgSpec),
|
||||||
|
UseArgs = gen_arg_uses(0, ArgSpec),
|
||||||
|
lists:flatten(io_lib:format("-spec ~s(~s) -> ~s.\n"
|
||||||
|
"~s(~s) ->\n"
|
||||||
|
" {~w, ~s}.\n\n",
|
||||||
|
[Function, ArgTypeSpecs, Type,
|
||||||
|
Function, Args, Name, UseArgs])).
|
||||||
|
|
||||||
|
gen_arg_type_specs([]) -> [];
|
||||||
|
gen_arg_type_specs([a]) -> "fate_arg()";
|
||||||
|
gen_arg_type_specs([is]) -> "aeb_fate_data:fate_string()";
|
||||||
|
gen_arg_type_specs([ii]) -> "aeb_fate_data:fate_integer()";
|
||||||
|
gen_arg_type_specs([li]) -> "[aeb_fate_data:fate_integer()]";
|
||||||
|
gen_arg_type_specs([t]) -> "aeb_fate_data:fate_type_type()";
|
||||||
|
gen_arg_type_specs([a | Args]) -> "fate_arg(), " ++ gen_arg_type_specs(Args);
|
||||||
|
gen_arg_type_specs([is | Args]) -> "aeb_fate_data:fate_string(), " ++ gen_arg_type_specs(Args);
|
||||||
|
gen_arg_type_specs([ii | Args]) -> "aeb_fate_data:fate_integer(), " ++ gen_arg_type_specs(Args);
|
||||||
|
gen_arg_type_specs([li | Args]) -> "[aeb_fate_data:fate_integer()], " ++ gen_arg_type_specs(Args);
|
||||||
|
gen_arg_type_specs([t | Args]) -> "aeb_fate_data:fate_type_type(), " ++ gen_arg_type_specs(Args).
|
||||||
|
|
||||||
|
|
||||||
|
gen_arg_names(_, []) ->
|
||||||
|
[];
|
||||||
|
gen_arg_names(N, [_]) -> io_lib:format("Arg~w", [N]);
|
||||||
|
gen_arg_names(N, [_|Args]) ->
|
||||||
|
io_lib:format("Arg~w, ", [N]) ++ gen_arg_names(N+1, Args).
|
||||||
|
|
||||||
|
gen_arg_uses(_, []) ->
|
||||||
|
[];
|
||||||
|
gen_arg_uses(N, [a]) -> io_lib:format("Arg~w", [N]);
|
||||||
|
gen_arg_uses(N, [is]) -> io_lib:format("{immediate, Arg~w}", [N]);
|
||||||
|
gen_arg_uses(N, [ii]) -> io_lib:format("{immediate, Arg~w}", [N]);
|
||||||
|
gen_arg_uses(N, [li]) -> io_lib:format("[{immediate, I} || I <- Arg~w]", [N]);
|
||||||
|
gen_arg_uses(N, [t]) -> io_lib:format("Arg~w", [N]);
|
||||||
|
gen_arg_uses(N, [a | Args]) ->
|
||||||
|
io_lib:format("Arg~w, ", [N]) ++ gen_arg_uses(N+1, Args);
|
||||||
|
gen_arg_uses(N, [is | Args]) ->
|
||||||
|
io_lib:format("{immediate, Arg~w}, ", [N]) ++ gen_arg_uses(N+1, Args);
|
||||||
|
gen_arg_uses(N, [ii | Args]) ->
|
||||||
|
io_lib:format("{immediate, Arg~w}, ", [N]) ++ gen_arg_uses(N+1, Args);
|
||||||
|
gen_arg_uses(N, [li | Args]) ->
|
||||||
|
io_lib:format("[{immediate, I} || I <- Arg~w], ", [N]) ++ gen_arg_uses(N+1, Args);
|
||||||
|
gen_arg_uses(N, [t | Args]) ->
|
||||||
|
io_lib:format("Arg~w, ", [N]) ++ gen_arg_uses(N+1, Args).
|
||||||
|
|
||||||
|
|
||||||
|
ops_exports(Module, HrlFile, Exports) ->
|
||||||
|
lists:flatten(io_lib:format(
|
||||||
|
"-module(~w).\n\n"
|
||||||
|
"-export([ ~s ]).\n\n"
|
||||||
|
"-include_lib(\"aebytecode/include/" ++ HrlFile ++"\").\n\n"
|
||||||
|
"%%====================================================================\n"
|
||||||
|
"%% API\n"
|
||||||
|
"%%====================================================================\n",
|
||||||
|
[Module, Exports])).
|
||||||
|
|
||||||
|
gen_mnemonic(#{opname := Name, macro := Macro}) ->
|
||||||
|
lists:flatten(io_lib:format("mnemonic(~21s) -> ~21w ;\n",
|
||||||
|
[Macro, Name])).
|
||||||
|
|
||||||
|
|
||||||
|
gen_m_to_op(#{opname := Name, macro := Macro}) ->
|
||||||
|
lists:flatten(io_lib:format("m_to_op(~21w) -> ~21s ;\n",
|
||||||
|
[Name, Macro])).
|
||||||
|
|
||||||
|
gen_args(#{macro := Macro, args := Args}) ->
|
||||||
|
lists:flatten(io_lib:format("args(~21s) -> ~2w ;\n",
|
||||||
|
[Macro, Args])).
|
||||||
|
|
||||||
|
gen_bb(#{macro := Macro, end_bb := EndBB}) ->
|
||||||
|
lists:flatten(io_lib:format("end_bb(~21s) -> ~w ;\n",
|
||||||
|
[Macro, EndBB])).
|
||||||
|
|
||||||
|
|
||||||
|
prelude(Doc) ->
|
||||||
|
"%%%-------------------------------------------------------------------\n"
|
||||||
|
"%%% @copyright (C) 2019, Aeternity Anstalt\n"
|
||||||
|
"%%%\n"
|
||||||
|
"%%% === === N O T E : This file is generated do not edit. === ===\n"
|
||||||
|
"%%%\n"
|
||||||
|
"%%% Source is in aeb_fate_generate_ops.erl\n"
|
||||||
|
"%%% @doc\n"
|
||||||
|
"%%% "++Doc++
|
||||||
|
"%%% @end\n"
|
||||||
|
"%%%-------------------------------------------------------------------\n\n".
|
||||||
|
|
||||||
|
|
||||||
|
gen_defines(#{opname := Name, opcode := OpCode}) ->
|
||||||
|
lists:flatten(io_lib:format("-define(~-17w, 16#~2.16.0b).\n", [Name, OpCode])).
|
||||||
|
|
||||||
|
gen([]) ->
|
||||||
|
[];
|
||||||
|
gen([{OpName, OpCode, Args, EndBB, Gas, FateFormat, Constructor, Doc} | Rest]) ->
|
||||||
|
Name = atom_to_list(OpName),
|
||||||
|
LowerName = string:to_lower(Name),
|
||||||
|
TypeName = "fate_" ++ LowerName ++ "()",
|
||||||
|
Macro = "?" ++ Name,
|
||||||
|
Type = case FateFormat of
|
||||||
|
atomic -> io_lib:format("~w", [OpName]);
|
||||||
|
ArgTypes ->
|
||||||
|
io_lib:format("{~w, ~s}", [OpName, expand_types(ArgTypes)])
|
||||||
|
end,
|
||||||
|
ConstructorType = atom_to_list(Constructor) ++ "/" ++ io_lib:format("~w", [Args]),
|
||||||
|
|
||||||
|
[#{ opname => OpName
|
||||||
|
, opcode => OpCode
|
||||||
|
, args => Args
|
||||||
|
, end_bb => EndBB
|
||||||
|
, format => FateFormat
|
||||||
|
, macro => Macro
|
||||||
|
, type_name => TypeName
|
||||||
|
, doc => Doc
|
||||||
|
, gas => Gas
|
||||||
|
, type => Type
|
||||||
|
, constructor => Constructor
|
||||||
|
, constructor_type => ConstructorType
|
||||||
|
}| gen(Rest)].
|
||||||
|
|
||||||
|
|
||||||
|
expand_types([]) -> "";
|
||||||
|
expand_types([T]) -> expand_type(T);
|
||||||
|
expand_types([T|Ts]) ->expand_type(T) ++ ", " ++ expand_types(Ts).
|
||||||
|
|
||||||
|
expand_type(a) -> "fate_arg()";
|
||||||
|
expand_type(is) -> "fate_arg_immediate(aeb_fate_data:fate_string())";
|
||||||
|
expand_type(ii) -> "fate_arg_immediate(aeb_fate_data:fate_integer())";
|
||||||
|
expand_type(li) -> "[fate_arg_immediate(aeb_fate_data:fate_integer())]";
|
||||||
|
expand_type(t) -> "aeb_fate_data:fate_type_type()".
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user