Compare commits

...

12 Commits

Author SHA1 Message Date
Thomas Arts
9d056dc620 Add eqc profile 2019-02-28 13:34:03 +01:00
Thomas Arts
a51a864059 Formatting differently 2019-02-28 13:33:47 +01:00
Thomas Arts
899bff9111 unit is printed () 2019-02-28 13:33:26 +01:00
Thomas Arts
b5daedaf95 Since Tag < Size, Size cannot be zero 2019-02-28 10:38:33 +01:00
Erik Stenman
8dd8e89c1e Rename NUMBER op to GENERATION and add MICROBLOCK instruction. 2019-02-28 08:13:26 +01:00
Erik Stenman
dd1a6a9c3d Generate tokens in scanner from definitions. 2019-02-28 07:55:51 +01:00
Erik Stenman
161b5a6106 Renumber opcodes. Add primops. 2019-02-27 17:47:08 +01:00
Erik Stenman
268208ec98 Use test target for ci. 2019-02-27 15:36:48 +01:00
Erik Stenman
9411a131fc Spell eunit the right way. 2019-02-27 15:34:06 +01:00
Erik Stenman
c624f4956c Test targets and cleanup. 2019-02-27 15:34:06 +01:00
Erik Stenman
ab150ce7f8 Generate the code from the makefile. Remove generated files. 2019-02-27 15:34:06 +01:00
Erik Stenman
c85af9e7f3 Generate code for fate ops from spec. 2019-02-27 15:34:06 +01:00
13 changed files with 583 additions and 1033 deletions

View File

@ -19,16 +19,16 @@ jobs:
- dialyzer-cache-v1-
- run:
name: Build
command: rebar3 compile
command: make
- run:
name: Static Analysis
command: rebar3 dialyzer
command: make dialyzer
- run:
name: Eunit
command: rebar3 eunit
command: make eunit
- run:
name: Common Tests
command: rebar3 ct
command: make test
- save_cache:
key: dialyzer-cache-v1-{{ .Branch }}-{{ .Revision }}
paths:

4
.gitignore vendored
View File

@ -10,5 +10,9 @@ rel/example_project
.rebar
aeb_asm_scan.erl
aeb_fate_asm_scan.erl
aeb_fate_asm_scan.xrl
_build/
aefateasm
include/aeb_fate_opcodes.hrl
src/aeb_fate_code.erl
src/aeb_fate_opcodes.erl

View File

@ -4,17 +4,38 @@ REBAR ?= rebar3
all: local
local:
local: src/aeb_fate_opcodes.erl src/aeb_fate_code.erl include/aeb_fate_opcodes.hrl src/aeb_fate_asm_scan.xrl
@$(REBAR) as local release
console:
console: local
@$(REBAR) as local shell
clean:
@$(REBAR) clean
rm -f src/aeb_fate_opcodes.erl
rm -f src/aeb_fate_code.erl
rm -f include/aeb_fate_opcodes.hrl
dialyzer: local
@$(REBAR) as local dialyzer
distclean: clean
@rm -rf _build/
eunit: local
@$(REBAR) as local eunit
test: local
@$(REBAR) as local eunit
ebin/aeb_fate_generate_ops.beam: src/aeb_fate_generate_ops.erl ebin
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
erl -pa ebin/ -noshell -s aeb_fate_generate_ops gen_and_halt src/ include/
ebin:
mkdir ebin

View File

@ -1,121 +0,0 @@
%% FATE opcodes
-define('NOP' , 16#00).
-define('RETURN' , 16#01).
-define('CALL' , 16#02).
-define('CALL_R' , 16#03).
-define('CALL_T' , 16#04).
-define('CALL_TR' , 16#05).
-define('JUMP' , 16#06).
-define('JUMPIF' , 16#07).
-define('SWITCH' , 16#08).
-define('PUSH' , 16#09).
-define('DUP' , 16#0a).
-define('POP' , 16#0b).
-define('STORE' , 16#10).
-define('ADD' , 16#11).
-define('MUL' , 16#12).
-define('SUB' , 16#13).
-define('DIV' , 16#14).
-define('MOD' , 16#15).
-define('POW' , 16#16).
-define('LT' , 16#17).
-define('GT' , 16#18).
-define('EQ' , 16#19).
-define('ELT' , 16#1a).
-define('EGT' , 16#1b).
-define('NEQ' , 16#1c).
-define('AND' , 16#1d).
-define('OR' , 16#1e).
-define('NOT' , 16#1f).
-define('TUPLE' , 16#20).
-define('ELEMENT' , 16#21).
-define('MAP_EMPTY' , 16#22).
-define('MAP_LOOKUP' , 16#23).
-define('MAP_UPDATE' , 16#24).
-define('MAP_DELETE' , 16#25).
-define('MAP_MEMBER' , 16#26).
-define('MAP_FROM_LIST' , 16#27).
-define('NIL' , 16#28).
-define('IS_NIL' , 16#29).
-define('CONS' , 16#2a).
-define('HD' , 16#2b).
-define('TL' , 16#2c).
-define('LENGTH' , 16#2d).
-define('STR_EQ' , 16#2e).
-define('STR_JOIN' , 16#2f).
-define('ADDR_TO_STR' , 16#30).
-define('STR_REVERSE' , 16#31).
-define('INT_TO_ADDR' , 16#32).
-define('VARIANT' , 16#33).
-define('VARIANT_TEST' , 16#34).
-define('VARIANT_ELEMENT', 16#35).
-define('BITS_NONE' , 16#36).
-define('BITS_ALL' , 16#37).
-define('BITS_SET' , 16#38).
-define('BITS_CLEAR' , 16#39).
-define('BITS_TEST' , 16#3a).
-define('BITS_SUM' , 16#3b).
-define('BITS_OR' , 16#3c).
-define('BITS_AND' , 16#3d).
-define('BITS_DIFF' , 16#3e).
-define('ADDRESS' , 16#3f).
-define('BALANCE' , 16#40).
-define('ORIGIN' , 16#41).
-define('CALLER' , 16#42).
-define('GASPRICE' , 16#43).
-define('BLOCKHASH' , 16#44).
-define('BENEFICIARY' , 16#45).
-define('TIMESTAMP' , 16#46).
-define('NUMBER' , 16#47).
-define('DIFFICULTY' , 16#48).
-define('GASLIMIT' , 16#49).
-define('GAS' , 16#4a).
-define('LOG0' , 16#4b).
-define('LOG1' , 16#4c).
-define('LOG2' , 16#4d).
-define('LOG3' , 16#4e).
-define('LOG4' , 16#4f).
-define('ABORT' , 16#50).
-define('EXIT' , 16#51).
-define('DEACTIVATE' , 16#52).
-define('INC' , 16#53).
-define('DEC' , 16#54).
-define('INT_TO_STR' , 16#55).
-define('SPEND' , 16#56).
-define('ORACLE_REGISTER', 16#57).
-define('ORACLE_QUERY' , 16#58).
-define('ORACLE_RESPOND' , 16#59).
-define('ORACLE_EXTEND' , 16#5a).
-define('ORACLE_GET_ANSWER', 16#5b).
-define('ORACLE_GET_QUESTION', 16#5c).
-define('ORACLE_QUERY_FEE', 16#5d).
-define('AENS_RESOLVE' , 16#5e).
-define('AENS_PRECLAIM' , 16#5f).
-define('AENS_CLAIM' , 16#60).
-define('AENS_UPDATE' , 16#61).
-define('AENS_TRANSFER' , 16#62).
-define('AENS_REVOKE' , 16#63).
-define('ECVERIFY' , 16#64).
-define('SHA3' , 16#65).
-define('SHA256' , 16#66).
-define('BLAKE2B' , 16#67).
-define('RETURNR' , 16#68).
-define('MAP_LOOKUPD' , 16#69).
-define('SWITCH_V2' , 16#6a).
-define('SWITCH_V3' , 16#6b).
-define('SWITCH_VN' , 16#6c).
-define('BITS_ALL_N' , 16#6d).
-define('BITS_NONEA' , 16#6e).
-define('BITS_ALLA' , 16#6f).
-define('DUPA' , 16#70).
-define('INCA' , 16#71).
-define('DECA' , 16#72).
-define('POPA' , 16#73).
-define('FUNCTION' , 16#fe).
-define('EXTEND' , 16#ff).
-define( COMMENT(X), {comment, X}).

View 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!
]}
]}.

View File

@ -10,10 +10,15 @@
%%% DUP
%%% Identifiers start with a lower case letter
%%% an_identifier
%%% References to function arguments start with arg
%%% References to function arguments start with arg followed by an integer
%%% arg0
%%% References to variables/registers start with var
%%% 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
%%%
%%% Immediates can be of 9 types:
%%% 1. Integers
%%% 42
@ -815,7 +820,7 @@ 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)];

View File

@ -0,0 +1,99 @@
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
%%%-------------------------------------------------------------------
%%% @copyright (C) 2019, aeternity Anstalt
%%% @doc
%%% Handling FATE code.
%%% @end
###REPLACEWITHNOTE###
%%%-------------------------------------------------------------------
Definitions.
DIGIT = [0-9]
HEXDIGIT = [0-9a-fA-F]
LOWER = [a-z_]
UPPER = [A-Z]
INT = {DIGIT}+
HEX = 0x{HEXDIGIT}+
HASH = #{HEXDIGIT}+
WS = [\000-\s]
ID = {LOWER}[a-zA-Z0-9_]*
Rules.
arg{INT} : {token, {arg, TokenLine, parse_arg(TokenChars)}}.
var{INT} : {token, {var, TokenLine, parse_var(TokenChars)}}.
a : {token, {stack, TokenLine, 0}}.
a{INT} : {token, {stack, TokenLine, parse_acc(TokenChars)}}.
true : {token, {boolean, TokenLine, true}}.
false : {token, {boolean, TokenLine, false}}.
###REPLACEWITHOPTOKENS###
FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}.
{ID} :
{token, {id, TokenLine, TokenChars}}.
{HEX} :
{token, {int, TokenLine, parse_hex(TokenChars)}}.
{INT} :
{token, {int, TokenLine, parse_int(TokenChars)}}.
{HASH} :
{token, {hash, TokenLine, parse_hash(TokenChars)}}.
%% Symbols
\-\> : {token, {'to', TokenLine}}.
\: : {token, {'to', TokenLine}}.
, : {token, {',', TokenLine}}.
\( : {token, {'(', TokenLine}}.
\) : {token, {')', TokenLine}}.
\[ : {token, {'[', TokenLine}}.
\] : {token, {']', TokenLine}}.
\{ : {token, {'{', TokenLine}}.
\} : {token, {'}', TokenLine}}.
;;.* :
{token, {comment, TokenLine, drop_prefix($;, TokenChars)}}.
\. : skip_token.
%% Whitespace ignore
{WS} : skip_token.
%% Comments (TODO: nested comments)
. : {error, "Unexpected token: " ++ TokenChars}.
Erlang code.
-export([scan/1]).
-dialyzer({nowarn_function, yyrev/2}).
-ignore_xref([format_error/1, string/2, token/2, token/3, tokens/2, tokens/3]).
-include_lib("aebytecode/include/aeb_fate_opcodes.hrl").
parse_hex("0x" ++ Chars) -> list_to_integer(Chars, 16).
parse_int(Chars) -> list_to_integer(Chars).
parse_arg("arg" ++ N) -> list_to_integer(N).
parse_var("var" ++ N) -> list_to_integer(N).
parse_acc("a" ++ N) -> list_to_integer(N).
parse_hash("#" ++ Chars) ->
N = list_to_integer(Chars, 16),
<<N:256>>.
scan(S) ->
string(S).
drop_prefix(C, [C|Rest]) ->
drop_prefix(C, Rest);
drop_prefix(_, Tail) -> Tail.

View File

@ -1,207 +0,0 @@
%%% -*- erlang-indent-level:4; indent-tabs-mode: nil -*-
%%%-------------------------------------------------------------------
%%% @copyright (C) 2019, aeternity Anstalt
%%% @doc
%%% Handling FATE code.
%%% @end
%%% Created : 9 Jan 2019
%%%-------------------------------------------------------------------
Definitions.
DIGIT = [0-9]
HEXDIGIT = [0-9a-fA-F]
LOWER = [a-z_]
UPPER = [A-Z]
INT = {DIGIT}+
HEX = 0x{HEXDIGIT}+
HASH = #{HEXDIGIT}+
WS = [\000-\s]
ID = {LOWER}[a-zA-Z0-9_]*
Rules.
arg{INT} : {token, {arg, TokenLine, parse_arg(TokenChars)}}.
var{INT} : {token, {var, TokenLine, parse_var(TokenChars)}}.
a : {token, {stack, TokenLine, 0}}.
a{INT} : {token, {stack, TokenLine, parse_acc(TokenChars)}}.
true : {token, {boolean, TokenLine, true}}.
false : {token, {boolean, TokenLine, false}}.
RETURN : {token, {mnemonic, TokenLine, 'RETURN'}}.
RETURNR : {token, {mnemonic, TokenLine, 'RETURNR'}}.
CALL : {token, {mnemonic, TokenLine, 'CALL'}}.
NOP : {token, {mnemonic, TokenLine, 'NOP'}}.
CALL_R : {token, {mnemonic, TokenLine, 'CALL_R'}}.
CALL_T : {token, {mnemonic, TokenLine, 'CALL_T'}}.
CALL_TR : {token, {mnemonic, TokenLine, 'CALL_TR'}}.
JUMP : {token, {mnemonic, TokenLine, 'JUMP'}}.
JUMPIF : {token, {mnemonic, TokenLine, 'JUMPIF'}}.
SWITCH_V2 : {token, {mnemonic, TokenLine, 'SWITCH_V2'}}.
SWITCH_V3 : {token, {mnemonic, TokenLine, 'SWITCH_V3'}}.
SWITCH_VN : {token, {mnemonic, TokenLine, 'SWITCH_VN'}}.
PUSH : {token, {mnemonic, TokenLine, 'PUSH'}}.
DUP : {token, {mnemonic, TokenLine, 'DUP'}}.
DUPA : {token, {mnemonic, TokenLine, 'DUPA'}}.
POP : {token, {mnemonic, TokenLine, 'POP'}}.
STORE : {token, {mnemonic, TokenLine, 'STORE'}}.
ADD : {token, {mnemonic, TokenLine, 'ADD'}}.
MUL : {token, {mnemonic, TokenLine, 'MUL'}}.
SUB : {token, {mnemonic, TokenLine, 'SUB'}}.
DIV : {token, {mnemonic, TokenLine, 'DIV'}}.
MOD : {token, {mnemonic, TokenLine, 'MOD'}}.
POW : {token, {mnemonic, TokenLine, 'POW'}}.
INC : {token, {mnemonic, TokenLine, 'INC'}}.
DEC : {token, {mnemonic, TokenLine, 'DEC'}}.
INCA : {token, {mnemonic, TokenLine, 'INCA'}}.
DECA : {token, {mnemonic, TokenLine, 'DECA'}}.
LT : {token, {mnemonic, TokenLine, 'LT'}}.
GT : {token, {mnemonic, TokenLine, 'GT'}}.
EQ : {token, {mnemonic, TokenLine, 'EQ'}}.
ELT : {token, {mnemonic, TokenLine, 'ELT'}}.
EGT : {token, {mnemonic, TokenLine, 'EGT'}}.
NEQ : {token, {mnemonic, TokenLine, 'NEQ'}}.
AND : {token, {mnemonic, TokenLine, 'AND'}}.
OR : {token, {mnemonic, TokenLine, 'OR'}}.
NOT : {token, {mnemonic, TokenLine, 'NOT'}}.
TUPLE : {token, {mnemonic, TokenLine, 'TUPLE'}}.
ELEMENT : {token, {mnemonic, TokenLine, 'ELEMENT'}}.
MAP_EMPTY : {token, {mnemonic, TokenLine, 'MAP_EMPTY'}}.
MAP_LOOKUP : {token, {mnemonic, TokenLine, 'MAP_LOOKUP'}}.
MAP_LOOKUPD : {token, {mnemonic, TokenLine, 'MAP_LOOKUPD'}}.
MAP_UPDATE : {token, {mnemonic, TokenLine, 'MAP_UPDATE'}}.
MAP_MEMBER : {token, {mnemonic, TokenLine, 'MAP_MEMBER'}}.
MAP_DELETE : {token, {mnemonic, TokenLine, 'MAP_DELETE'}}.
MAP_FROM_LIST : {token, {mnemonic, TokenLine, 'MAP_FROM_LIST'}}.
NIL : {token, {mnemonic, TokenLine, 'NIL'}}.
IS_NIL : {token, {mnemonic, TokenLine, 'IS_NIL'}}.
CONS : {token, {mnemonic, TokenLine, 'CONS'}}.
HD : {token, {mnemonic, TokenLine, 'HD'}}.
TL : {token, {mnemonic, TokenLine, 'TL'}}.
LENGTH : {token, {mnemonic, TokenLine, 'LENGTH'}}.
STR_EQ : {token, {mnemonic, TokenLine, 'STR_EQ'}}.
STR_JOIN : {token, {mnemonic, TokenLine, 'STR_JOIN'}}.
INT_TO_STR : {token, {mnemonic, TokenLine, 'INT_TO_STR'}}.
ADDR_TO_STR : {token, {mnemonic, TokenLine, 'ADDR_TO_STR'}}.
STR_REVERSE : {token, {mnemonic, TokenLine, 'STR_REVERSE'}}.
INT_TO_ADDR : {token, {mnemonic, TokenLine, 'INT_TO_ADDR'}}.
VARIANT : {token, {mnemonic, TokenLine, 'VARIANT'}}.
VARIANT_TEST : {token, {mnemonic, TokenLine, 'VARIANT_TEST'}}.
VARIANT_ELEMENT : {token, {mnemonic, TokenLine, 'VARIANT_ELEMENT'}}.
BITS_NONE : {token, {mnemonic, TokenLine, 'BITS_NONE'}}.
BITS_NONEA : {token, {mnemonic, TokenLine, 'BITS_NONEA'}}.
BITS_ALL : {token, {mnemonic, TokenLine, 'BITS_ALL'}}.
BITS_ALLA : {token, {mnemonic, TokenLine, 'BITS_ALLA'}}.
BITS_ALL_N : {token, {mnemonic, TokenLine, 'BITS_ALL_N'}}.
BITS_SET : {token, {mnemonic, TokenLine, 'BITS_SET'}}.
BITS_CLEAR : {token, {mnemonic, TokenLine, 'BITS_CLEAR'}}.
BITS_TEST : {token, {mnemonic, TokenLine, 'BITS_TEST'}}.
BITS_SUM : {token, {mnemonic, TokenLine, 'BITS_SUM'}}.
BITS_OR : {token, {mnemonic, TokenLine, 'BITS_OR'}}.
BITS_AND : {token, {mnemonic, TokenLine, 'BITS_AND'}}.
BITS_DIFF : {token, {mnemonic, TokenLine, 'BITS_DIFF'}}.
ADDRESS : {token, {mnemonic, TokenLine, 'ADDRESS'}}.
BALANCE : {token, {mnemonic, TokenLine, 'BALANCE'}}.
ORIGIN : {token, {mnemonic, TokenLine, 'ORIGIN'}}.
CALLER : {token, {mnemonic, TokenLine, 'CALLER'}}.
GASPRICE : {token, {mnemonic, TokenLine, 'GASPRICE'}}.
BLOCKHASH : {token, {mnemonic, TokenLine, 'BLOCKHASH'}}.
BENEFICIARY : {token, {mnemonic, TokenLine, 'BENEFICIARY'}}.
TIMESTAMP : {token, {mnemonic, TokenLine, 'TIMESTAMP'}}.
NUMBER : {token, {mnemonic, TokenLine, 'NUMBER'}}.
DIFFICULTY : {token, {mnemonic, TokenLine, 'DIFFICULTY'}}.
GASLIMIT : {token, {mnemonic, TokenLine, 'GASLIMIT'}}.
GAS : {token, {mnemonic, TokenLine, 'GAS'}}.
LOG0 : {token, {mnemonic, TokenLine, 'LOG0'}}.
LOG1 : {token, {mnemonic, TokenLine, 'LOG1'}}.
LOG2 : {token, {mnemonic, TokenLine, 'LOG2'}}.
LOG3 : {token, {mnemonic, TokenLine, 'LOG3'}}.
LOG4 : {token, {mnemonic, TokenLine, 'LOG4'}}.
ABORT : {token, {mnemonic, TokenLine, 'ABORT'}}.
EXIT : {token, {mnemonic, TokenLine, 'EXIT'}}.
DEACTIVATE : {token, {mnemonic, TokenLine, 'DEACTIVATE'}}.
COMMENT : {token, {mnemonic, TokenLine, 'COMMENT'}}.
FUNCTION : {token, {function, TokenLine, 'FUNCTION' }}.
{ID} :
{token, {id, TokenLine, TokenChars}}.
{HEX} :
{token, {int, TokenLine, parse_hex(TokenChars)}}.
{INT} :
{token, {int, TokenLine, parse_int(TokenChars)}}.
{HASH} :
{token, {hash, TokenLine, parse_hash(TokenChars)}}.
%% Symbols
\-\> : {token, {'to', TokenLine}}.
\: : {token, {'to', TokenLine}}.
, : {token, {',', TokenLine}}.
\( : {token, {'(', TokenLine}}.
\) : {token, {')', TokenLine}}.
\[ : {token, {'[', TokenLine}}.
\] : {token, {']', TokenLine}}.
\{ : {token, {'{', TokenLine}}.
\} : {token, {'}', TokenLine}}.
;;.* :
{token, {comment, TokenLine, drop_prefix($;, TokenChars)}}.
\. : skip_token.
%% Whitespace ignore
{WS} : skip_token.
%% Comments (TODO: nested comments)
. : {error, "Unexpected token: " ++ TokenChars}.
Erlang code.
-export([scan/1]).
-dialyzer({nowarn_function, yyrev/2}).
-ignore_xref([format_error/1, string/2, token/2, token/3, tokens/2, tokens/3]).
-include_lib("aebytecode/include/aeb_fate_opcodes.hrl").
parse_hex("0x" ++ Chars) -> list_to_integer(Chars, 16).
parse_int(Chars) -> list_to_integer(Chars).
parse_arg("arg" ++ N) -> list_to_integer(N).
parse_var("var" ++ N) -> list_to_integer(N).
parse_acc("a" ++ N) -> list_to_integer(N).
parse_hash("#" ++ Chars) ->
N = list_to_integer(Chars, 16),
<<N:256>>.
scan(S) ->
string(S).
drop_prefix(C, [C|Rest]) ->
drop_prefix(C, Rest);
drop_prefix(_, Tail) -> Tail.

View File

@ -1,303 +0,0 @@
-module(aeb_fate_code).
-export([ return/0
, return/1
, call/1
, call_t/1
, call_r/2
, call_tr/2
, jump/1
, jumpif/2
, switch/3
, switch/4
, switch/5
, switch/6
, push/1
, inc/0
, inc/1
, dec/0
, dec/1
, add/3
, sub/3
, mul/3
, divide/3
, modulo/3
, pow/3
, lt/3
, gt/3
, elt/3
, egt/3
, eq/3
, neq/3
, and_op/3
, or_op/3
, not_op/2
, tuple/1
, element_op/4
, map_empty/1
, map_lookup/3
, map_lookup/4
, map_update/4
, map_member/3
, map_from_list/2
, nil/1
, is_nil/2
, cons/3
, hd/2
, tl/2
, length/2
, str_eq/3
, str_join/3
, int_to_str/2
, addr_to_str/2
, str_reverse/2
, int_to_addr/2
, variant_test/3
, variant_element/3
, variant/4
, bits_none/0
, bits_none/1
, bits_all/0
, bits_all/1
, bits_all_n/2
, bits_set/3
, bits_clear/3
, bits_test/3
, bits_sum/2
, bits_or/3
, bits_and/3
, bits_diff/3
, dup/0
, dup/1
, pop/0
, store/2
, nop/0
]).
-define(i(__X__), {immediate, __X__ }).
return() ->
'RETURN'.
return(Arg) ->
{'RETURNR', Arg}.
call(Function) when is_binary(Function)->
{'CALL', ?i(Function) }.
call_t(Function) when is_binary(Function) ->
{'CALL_T', ?i(Function)}.
call_r(Contract, Function) when is_binary(Function) ->
{'CALL_R', Contract, ?i(Function)}.
call_tr(Contract, Function) when is_binary(Function) ->
{'CALL_TR', Contract, ?i(Function)}.
jump(BB) when is_integer(BB) ->
{'JUMP', ?i(BB)}.
jumpif(Arg, BB) when is_integer(BB) ->
{'JUMPIF', Arg, ?i(BB)}.
switch(Arg, BB1, BB2) when is_integer(BB1),
is_integer(BB2) ->
{'SWITCH_V2', Arg, ?i(BB1), ?i(BB2)}.
switch(Arg, BB1, BB2, BB3) when is_integer(BB1),
is_integer(BB2),
is_integer(BB3) ->
{'SWITCH_V3', Arg, ?i(BB1), ?i(BB2), ?i(BB3)}.
switch(Arg, BB1, BB2, BB3, BB4) when is_integer(BB1),
is_integer(BB2),
is_integer(BB3),
is_integer(BB4) ->
{'SWITCH_V4', Arg, ?i(BB1), ?i(BB2), ?i(BB3), ?i(BB4)}.
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)}.
push(Arg) ->
{'PUSH', Arg}.
inc() ->
'INCA'.
inc(Arg) ->
{'INC', Arg}.
dec() ->
'DECA'.
dec(Arg) ->
{'DEC', Arg}.
add(Dest, Left, Right) ->
{'ADD', Dest, Left, Right}.
sub(Dest, Left, Right) ->
{'SUB', Dest, Left, Right}.
mul(Dest, Left, Right) ->
{'MUL', Dest, Left, Right}.
divide(Dest, Left, Right) ->
{'DIV', Dest, Left, Right}.
modulo(Dest, Left, Right) ->
{'MOD', Dest, Left, Right}.
pow(Dest, Left, Right) ->
{'POW', Dest, Left, Right}.
lt(Dest, Left, Right) ->
{'LT', Dest, Left, Right}.
gt(Dest, Left, Right) ->
{'GT', Dest, Left, Right}.
elt(Dest, Left, Right) ->
{'ELT', Dest, Left, Right}.
egt(Dest, Left, Right) ->
{'EGT', Dest, Left, Right}.
eq(Dest, Left, Right) ->
{'EQ', Dest, Left, Right}.
neq(Dest, Left, Right) ->
{'NEQ', Dest, Left, Right}.
and_op(Dest, Left, Right) ->
{'AND', Dest, Left, Right}.
or_op(Dest, Left, Right) ->
{'OR', Dest, Left, Right}.
not_op(Dest, Arg) ->
{'NOT', Dest, Arg}.
tuple(Size) when is_integer(Size) ->
{'TUPLE', ?i(Size)}.
element_op(Type, Dest, N, T) ->
{'ELEMENT', Type, Dest, N, T}.
map_empty(Dest) ->
{'MAP_EMPTY', Dest}.
map_lookup(Dest, Map, Key) ->
{'MAP_LOOKUP', Dest, Map, Key}.
map_lookup(Dest, Map, Key, Default) ->
{'MAP_LOOKUPD', Dest, Map, Key, Default}.
map_update(Dest, Map, Key, Value) ->
{'MAP_UPDATE', Dest, Map, Key, Value}.
map_member(Dest, Map, Key) ->
{'MAP_MEMBER', Dest, Map, Key}.
map_from_list(Dest, List) ->
{'MAP_MEMBER', Dest, List}.
nil(Dest) ->
{'NIL', Dest}.
is_nil(Dest, List) ->
{'IS_NIL', Dest, List}.
cons(Dest, Hd, Tl) ->
{'CONS', Dest, Hd, Tl}.
hd(Dest, List) ->
{'HD', Dest, List}.
tl(Dest, List) ->
{'TL', Dest, List}.
length(Dest, List) ->
{'LENGTH', Dest, List}.
str_eq(Dest, Str1, Str2) ->
{'STR_EQ', Dest, Str1, Str2}.
str_join(Dest, Str1, Str2) ->
{'STR_JOIN', Dest, Str1, Str2}.
int_to_str(Dest, Str) ->
{'INT_TO_STR', Dest, Str}.
addr_to_str(Dest, Str) ->
{'ADDR_TO_STR', Dest, Str}.
str_reverse(Dest, Str) ->
{'STR_REVERSE', Dest, Str}.
int_to_addr(Dest, Str) ->
{'INT_TO_ADDR', Dest, Str}.
variant_test(Dest, Variant, Tag) ->
{'VARIANT_TEST', Dest, Variant, Tag}.
variant_element( Dest, Variant, Index) ->
{'VARIANT_ELEMENT', Dest, Variant, Index}.
variant(Dest, SizeA, TagA, ElementsA) ->
{'VARIANT', Dest, SizeA, TagA, ElementsA}.
bits_none() ->
'BITS_NONEA'.
bits_none(To) ->
{'BITS_NONE', To}.
bits_all() ->
'BITS_ALLA'.
bits_all(To) ->
{'BITS_ALL', To}.
bits_all_n(To, N) ->
{'BITS_ALL_N', To, N}.
bits_set(To, Bits, Bit) ->
{'BITS_SET', To, Bits, Bit}.
bits_clear(To, Bits, Bit) ->
{'BITS_CLEAR', To, Bits, Bit}.
bits_test(To, Bits, Bit) ->
{'BITS_TEST', To, Bits, Bit}.
bits_sum(To, Bits) ->
{'BITS_SUM', To, Bits}.
bits_or(To, Bits, Bit) ->
{'BITS_OR', To, Bits, Bit}.
bits_and(To, Bits, Bit) ->
{'BITS_AND', To, Bits, Bit}.
bits_diff(To, Bits, Bit) ->
{'BITS_DIFF', To, Bits, Bit}.
dup() ->
'DUPA'.
dup(N) when is_integer(N) ->
{'DUP', ?i(N)}.
pop() ->
'POP'.
store(Var, What) ->
{'STORE', Var, What}.
nop() ->
'NOP'.

View File

@ -15,10 +15,18 @@
-type fate_variant() :: ?FATE_VARIANT_T.
-type fate_void() :: ?FATE_VOID_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() ::
fate_boolean()
| fate_integer()
@ -30,11 +38,21 @@
| fate_address()
| fate_variant()
| fate_map()
| fate_list()
| fate_tuple()
| fate_void(). %% Not sure we need this.
| fate_type_type().
-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
, make_boolean/1
@ -111,35 +129,29 @@ decode(M) when ?IS_FATE_MAP(M) ->
-spec format(fate_type()) -> iolist().
format(I) when ?IS_FATE_INTEGER(I) -> integer_to_list(?MAKE_FATE_INTEGER(I));
format(?FATE_VOID) -> "void";
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

View File

@ -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
>>.

View File

@ -0,0 +1,402 @@
-module(aeb_fate_generate_ops).
-export([ gen_and_halt/1
, generate/0]).
gen_and_halt([SrcDirArg, IncludeDirArg]) ->
generate(atom_to_list(SrcDirArg),
atom_to_list(IncludeDirArg)),
halt().
generate() ->
generate("src/", "include/").
generate(Src, Include) ->
Ops = gen(ops_defs()),
%% io:format("ops: ~p\n", [Ops]),
HrlFile = Include ++ "aeb_fate_opcodes.hrl",
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).
%% TODO: Some real gas numbers...
ops_defs() ->
%% Opname, Opcode, args, end_bb, gas, format, Constructor, Documentation
[ { 'RETURN', 16#00, 0, true, 2, atomic, return, "Return from function call pop stack to arg0. The type of the retun value has to match the return type of the function."}
, { 'RETURNR', 16#01, 1, true, 2, [a], returnr, "Return from function call copy Arg0 to arg0. The type of the retun value has to match the return type of the function."}
, { 'CALL', 16#02, 1, true, 4, [is], call, "Call given function with args on stack. The types of the arguments has to match the argument typs of the function."}
, { 'CALL_R', 16#03, 2, true, 8, [a,is], call_r, "Remote call to given contract and function. The types of the arguments has to match the argument typs of the function."}
, { 'CALL_T', 16#04, 1, true, 4, [is], call_t, "Tail call to given function. The types of the arguments has to match the argument typs of the function. And the return type of the called function has to match the type of the current function."}
, { 'CALL_TR', 16#05, 2, true, 8, [a,is], call_tr, "Remote tail call to given contract and function. The types of the arguments has to match the argument typs of the function. And the return type of the called function has to match the type of the current function."}
, { 'JUMP', 16#06, 1, true, 3, [ii], jump, "Jump to a basic block. The basic block has to exist in the current function."}
, { 'JUMPIF', 16#07, 2, true, 4, [a,ii], jumpif, "Conditional jump to a basic block. If Arg0 then jump to Arg1."}
, { 'SWITCH_V2', 16#08, 3, true, 4, [a,ii,ii], switch, "Conditional jump to a basic block on variant tag."}
, { 'SWITCH_V3', 16#09, 4, true, 4, [a,ii,ii,ii], switch, "Conditional jump to a basic block on variant tag."}
, { 'SWITCH_VN', 16#0a, 2, true, 4, [a,li], switch, "Conditional jump to a basic block on variant tag."}
, { 'PUSH', 16#0b, 1, false, 2, [a], push, "Push argument to stack."}
, { 'DUPA', 16#0c, 0, false, 3, atomic, dup, "push copy of accumulator on stack."}
, { 'DUP', 16#0d, 1, false, 3, [a], dup, "push Arg0 stack pos on top of stack."}
, { 'POP', 16#0e, 1, false, 3, [a], pop, "Arg0 := top of stack."}
, { 'STORE', 16#0f, 2, false, 3, [a,a], store, "Arg0 := Arg1."}
, { 'INCA', 16#10, 0, false, 2, atomic, inc, "Increment accumulator."}
, { 'INC', 16#11, 1, false, 2, [a], inc, "Increment argument."}
, { 'DECA', 16#12, 0, false, 2, atomic, dec, "Decrement accumulator."}
, { 'DEC', 16#13, 1, false, 2, [a], dec, "Decrement argument."}
, { 'ADD', 16#14, 3, false, 3, [a,a,a], add, "Arg0 := Arg1 + Arg2."}
, { 'SUB', 16#15, 3, false, 3, [a,a,a], sub, "Arg0 := Arg1 - Arg2."}
, { 'MUL', 16#16, 3, false, 3, [a,a,a], mul, "Arg0 := Arg1 * Arg2."}
, { 'DIV', 16#17, 3, false, 3, [a,a,a], divide, "Arg0 := Arg1 / Arg2."}
, { 'MOD', 16#18, 3, false, 3, [a,a,a], modulo, "Arg0 := Arg1 mod Arg2."}
, { 'POW', 16#19, 3, false, 3, [a,a,a], pow, "Arg0 := Arg1 ^ Arg2."}
, { 'LT', 16#20, 3, false, 3, [a,a,a], lt, "Arg0 := Arg1 < Arg2."}
, { 'GT', 16#21, 3, false, 3, [a,a,a], gt, "Arg0 := Arg1 > Arg2."}
, { 'EQ', 16#22, 3, false, 3, [a,a,a], eq, "Arg0 := Arg1 = Arg2."}
, { 'ELT', 16#23, 3, false, 3, [a,a,a], elt, "Arg0 := Arg1 =< Arg2."}
, { 'EGT', 16#24, 3, false, 3, [a,a,a], egt, "Arg0 := Arg1 >= Arg2."}
, { 'NEQ', 16#25, 3, false, 3, [a,a,a], neq, "Arg0 := Arg1 /= Arg2."}
, { 'AND', 16#26, 3, false, 3, [a,a,a], and_op, "Arg0 := Arg1 and Arg2."}
, { 'OR', 16#27, 3, false, 3, [a,a,a], or_op, "Arg0 := Arg1 or Arg2."}
, { 'NOT', 16#28, 2, false, 3, [a,a], not_op, "Arg0 := not Arg1."}
, { 'TUPLE', 16#29, 1, false, 3, [ii], tuple, "Create a tuple of size = Arg0. Elements on stack."}
, { 'ELEMENT', 16#2a, 4, false, 3, [t,a,a,a], element_op, "Arg1 := element(Arg2, Arg3). The element should be of type Arg1"}
, { 'MAP_EMPTY', 16#2b, 1, false, 3, [a], map_empty, "Arg0 := #{}."}
, { 'MAP_LOOKUP', 16#2c, 3, false, 3, [a,a,a], map_lookup, "Arg0 := lookup key Arg2 in map Arg1."}
, { 'MAP_LOOKUPD', 16#2d, 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#2e, 4, false, 3, [a,a,a,a], map_update, "Arg0 := update key Arg2 in map Arg1 with value Arg3."}
, { 'MAP_DELETE', 16#2f, 3, false, 3, [a,a,a], map_delete, "Arg0 := delete key Arg2 from map Arg1."}
, { 'MAP_MEMBER', 16#30, 3, false, 3, [a,a,a], map_member, "Arg0 := true if key Arg2 is in map Arg1."}
, { 'MAP_FROM_LIST',16#31, 2, false, 3, [a,a], map_from_list, "Arg0 := make a map from (key, value) list in Arg1."}
, { 'NIL', 16#32, 1, false, 3, [a], nil, "Arg0 := []."}
, { 'IS_NIL', 16#33, 2, false, 3, [a,a], is_nil, "Arg0 := true if Arg1 == []."}
, { 'CONS', 16#34, 3, false, 3, [a,a,a], cons, "Arg0 := [Arg1|Arg2]."}
, { 'HD', 16#35, 2, false, 3, [a,a], hd, "Arg0 := head of list Arg1."}
, { 'TL', 16#36, 2, false, 3, [a,a], tl, "Arg0 := tail of list Arg1."}
, { 'LENGTH', 16#37, 2, false, 3, [a,a], length, "Arg0 := length of list Arg1."}
, { 'STR_EQ', 16#38, 3, false, 3, [a,a,a], str_eq, "Arg0 := true iff the strings Arg1 and Arg2 are the same."}
, { 'STR_JOIN', 16#39, 3, false, 3, [a,a,a], str_join, "Arg0 := string Arg1 followed by string Arg2."}
, { 'INT_TO_STR', 16#40, 2, false, 3, [a,a], int_to_str, "Arg0 := turn integer Arg1 into a string."}
, { 'ADDR_TO_STR', 16#41, 2, false, 3, [a,a], addr_to_str, "Arg0 := turn address Arg1 into a string."}
, { 'STR_REVERSE', 16#42, 2, false, 3, [a,a], str_reverse, "Arg0 := the reverse of string Arg1."}
, { 'INT_TO_ADDR', 16#43, 2, false, 3, [a,a], int_to_addr, "Arg0 := turn integer Arg1 into an address."}
, { 'VARIANT', 16#44, 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#45, 3, false, 3, [a,a,a], variant_test, "Arg0 := true if variant Arg1 has the tag Arg2."}
, { 'VARIANT_ELEMENT',16#46, 3, false, 3, [a,a,a], variant_element, "Arg0 := element number Arg2 from variant Arg1."}
, { 'BITS_NONEA', 16#47, 0, false, 3, atomic, bits_none, "accumulator := empty bitmap."}
, { 'BITS_NONE', 16#48, 1, false, 3, [a], bits_none, "Arg0 := empty bitmap."}
, { 'BITS_ALLA', 16#49, 0, false, 3, atomic, bits_all, "accumulator := full bitmap."}
, { 'BITS_ALL', 16#50, 1, false, 3, [a], bits_all, "Arg0 := full bitmap."}
, { 'BITS_ALL_N', 16#51, 2, false, 3, [a,a], bits_all_n, "Arg0 := bitmap with Arg1 bits set."}
, { 'BITS_SET', 16#52, 3, false, 3, [a,a,a], bits_set, "Arg0 := set bit Arg2 of bitmap Arg1."}
, { 'BITS_CLEAR', 16#53, 3, false, 3, [a,a,a], bits_clear, "Arg0 := clear bit Arg2 of bitmap Arg1."}
, { 'BITS_TEST', 16#54, 3, false, 3, [a,a,a], bits_test, "Arg0 := true if bit Arg2 of bitmap Arg1 is set."}
, { 'BITS_SUM', 16#55, 2, false, 3, [a,a], bits_sum, "Arg0 := sum of set bits in bitmap Arg1. Exception if infinit bitmap."}
, { 'BITS_OR', 16#56, 3, false, 3, [a,a,a], bits_or, "Arg0 := Arg1 v Arg2."}
, { 'BITS_AND', 16#57, 3, false, 3, [a,a,a], bits_and, "Arg0 := Arg1 ^ Arg2."}
, { 'BITS_DIFF', 16#58, 3, false, 3, [a,a,a], bits_diff, "Arg0 := Arg1 - Arg2."}
, { 'ADDRESS', 16#59, 1, false, 3, [a], address, "Arg0 := The current contract address."}
, { 'BALANCE', 16#5a, 1, false, 3, [a], balance, "Arg0 := The current contract address."}
, { 'ORIGIN', 16#5b, 1, false, 3, [a], origin, "Arg0 := Address of contract called by the call transaction."}
, { 'CALLER', 16#5c, 1, false, 3, [a], caller, "Arg0 := The address that signed the call transaction."}
, { 'GASPRICE', 16#5d, 1, false, 3, [a], gasprice, "Arg0 := The current gas price."}
, { 'BLOCKHASH', 16#5e, 1, false, 3, [a], blockhash, "Arg0 := The current blockhash."} %% TODO: Do we support has at height?
, { 'BENEFICIARY', 16#5f, 1, false, 3, [a], beneficiary, "Arg0 := The address of the current beneficiary."}
, { 'TIMESTAMP', 16#60, 1, false, 3, [a], timestamp, "Arg0 := The current timestamp. Unrelaiable, don't use for anything."}
, { 'GENERATION', 16#61, 1, false, 3, [a], generation, "Arg0 := The block height of the cureent generation."}
, { 'MICROBLOCK', 16#62, 1, false, 3, [a], microblock, "Arg0 := The current micro block number."}
, { 'DIFFICULTY', 16#63, 1, false, 3, [a], difficulty, "Arg0 := The current difficulty."}
, { 'GASLIMIT', 16#64, 1, false, 3, [a], gaslimit, "Arg0 := The current gaslimit."}
, { 'GAS', 16#65, 1, false, 3, [a], gas, "Arg0 := The amount of gas left."}
, { 'LOG0', 16#66, 2, false, 3, [a,a], log, "Create a log message in the call object."}
, { 'LOG1', 16#67, 3, false, 3, [a,a,a], log, "Create a log message with one topic in the call object."}
, { 'LOG2', 16#68, 4, false, 3, [a,a,a,a], log, "Create a log message with two topics in the call object."}
, { 'LOG3', 16#69, 5, false, 3, [a,a,a,a,a], log, "Create a log message with three topics in the call object."}
, { 'LOG4', 16#6a, 6, false, 3, [a,a,a,a,a,a], log, "Create a log message with four topics in the call object."}
, { 'DEACTIVATE', 16#6b, 0, false, 3, atomic, deactivate, "Mark the current contract for deactication."}
%% Transaction ops
, { 'SPEND', 16#6c, 2, false,3, [a,a], spend, "Transfer Arg0 tokens to account Arg1. (If the contract account has at least that many tokens."}
, { 'ORACLE_REGISTER', 16#6d, 6, false,3, [a,a,a,a,a,a], oracle_register, "Mark the current contract for deactication."}
%% TODO:
, { 'ORACLE_QUERY', 16#6e, 0, false,3, atomic, oracle_query, ""}
, { 'ORACLE_RESPOND', 16#6f, 0, false,3, atomic, oracle_respond, ""}
, { 'ORACLE_EXTEND', 16#70, 0, false,3, atomic, oracle_extend, ""}
, { 'ORACLE_GET_ANSWER', 16#71, 0, false,3, atomic, oracle_get_answer, ""}
, { 'ORACLE_GET_QUESTION', 16#72, 0, false,3, atomic,oracle_get_question, ""}
, { 'ORACLE_QUERY_FEE', 16#73, 0, false,3, atomic, oracle_query_fee, ""}
, { 'AENS_RESOLVE', 16#74, 0, false,3, atomic, aens_resolve, ""}
, { 'AENS_PRECLAIM', 16#75, 0, false,3, atomic, aens_preclaim, ""}
, { 'AENS_CLAIM', 16#76, 0, false,3, atomic, aens_claim, ""}
, { 'AENS_UPDATE', 16#77, 0, false,3, atomic, aend_update, ""}
, { 'AENS_TRANSFER', 16#78, 0, false,3, atomic, aens_transfer, ""}
, { 'AENS_REVOKE', 16#79, 0, false,3, atomic, aens_revoke, ""}
, { 'ECVERIFY', 16#7a, 0, false,3, atomic, ecverify, ""}
, { 'SHA3', 16#7b, 0, false,3, atomic, sha3, ""}
, { 'SHA256', 16#7c, 0, false,3, atomic, sha256, ""}
, { 'BLAKE2B', 16#7d, 0, false,3, atomic, blake2b, ""}
, {'ABORT', 16#fb, 1, false, 3, [a], abort, "Abort execution (dont use all gas) with error message in Arg0."}
, {'EXIT', 16#fc, 1, false, 3, [a], exit, "Abort execution (use upp all gas) with error message in Arg0."}
, { 'NOP', 16#fd, 0, false, 1, atomic, nop, "The no op. does nothing."}
%% FUNCTION 16#fe "Function declaration and entrypoint."
%% EXTEND 16#ff "Reserved for future extensions beyond one byte opcodes."
].
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]),
io:format(File, "~s",
["-define('FUNCTION' , 16#fe).\n"
"-define('EXTEND' , 16#ff).\n\n"]),
file:close(File).
generate_opcodes_ops(Modulename, HrlFile, SrcDir, Ops) ->
Filename = SrcDir ++ 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, SrcDir, Ops) ->
Filename = SrcDir ++ 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 ~-26s :: ~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/" ++ 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(~-26w, 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()".
generate_scanner(TemplateFile, Outfile, Path, Ops) ->
{ok, Template} = file:read_file(filename:join(Path,TemplateFile)),
Tokens = lists:flatten([gen_token(Op) || Op <- Ops]),
NewFile = insert_tokens_in_template(Template, Tokens),
file:write_file(filename:join(Path, Outfile), NewFile).
gen_token(#{opname := OpName}) ->
Name = atom_to_list(OpName),
io_lib:format("~-28s: {token, {mnemonic, TokenLine, ~w}}.\n",
[Name, OpName]).
insert_tokens_in_template(<<"###REPLACEWITHOPTOKENS###", Rest/binary >>, Tokens) ->
[Tokens, Rest];
insert_tokens_in_template(<<"###REPLACEWITHNOTE###", Rest/binary >>, Tokens) ->
[
"%%%\n"
"%%% === === N O T E : This file is generated do not edit. === ===\n"
"%%%\n"
"%%% Source is in aeb_fate_generate_ops.erl\n"
"%%% and aeb_fate_asm_scan.template"
| insert_tokens_in_template(Rest, Tokens)];
insert_tokens_in_template(<<B,Rest/binary>>, Tokens) ->
[B|insert_tokens_in_template(Rest, Tokens)].

View File

@ -1,363 +0,0 @@
%%%-------------------------------------------------------------------
%%% @copyright (C) 2019, Aeternity Anstalt
%%% @doc
%%% Opcodes
%%% @end
%%%-------------------------------------------------------------------
-module(aeb_fate_opcodes).
-export([ args/1
, end_bb/1
, mnemonic/1
, m_to_op/1
, opcode/1
]).
-include_lib("aebytecode/include/aeb_fate_opcodes.hrl").
%%====================================================================
%% API
%%====================================================================
opcode(X) when X >= 0, X =< 255 -> X;
opcode({comment,X}) -> ?COMMENT(X).
mnemonic(?NOP) -> 'NOP' ;
mnemonic(?RETURN) -> 'RETURN' ;
mnemonic(?CALL) -> 'CALL' ;
mnemonic(?CALL_R) -> 'CALL_R' ;
mnemonic(?CALL_T) -> 'CALL_T' ;
mnemonic(?CALL_TR) -> 'CALL_TR' ;
mnemonic(?JUMP) -> 'JUMP' ;
mnemonic(?JUMPIF) -> 'JUMPIF' ;
mnemonic(?PUSH) -> 'PUSH' ;
mnemonic(?DUP) -> 'DUP' ;
mnemonic(?DUPA) -> 'DUPA' ;
mnemonic(?POP) -> 'POP' ;
mnemonic(?STORE) -> 'STORE' ;
mnemonic(?ADD) -> 'ADD' ;
mnemonic(?MUL) -> 'MUL' ;
mnemonic(?SUB) -> 'SUB' ;
mnemonic(?DIV) -> 'DIV' ;
mnemonic(?MOD) -> 'MOD' ;
mnemonic(?POW) -> 'POW' ;
mnemonic(?LT) -> 'LT' ;
mnemonic(?GT) -> 'GT' ;
mnemonic(?EQ) -> 'EQ' ;
mnemonic(?ELT) -> 'ELT' ;
mnemonic(?EGT) -> 'EGT' ;
mnemonic(?NEQ) -> 'NEQ' ;
mnemonic(?AND) -> 'AND' ;
mnemonic(?OR) -> 'OR' ;
mnemonic(?NOT) -> 'NOT' ;
mnemonic(?TUPLE) -> 'TUPLE' ;
mnemonic(?ELEMENT) -> 'ELEMENT' ;
mnemonic(?MAP_EMPTY) -> 'MAP_EMPTY' ;
mnemonic(?MAP_LOOKUP) -> 'MAP_LOOKUP' ;
mnemonic(?MAP_UPDATE) -> 'MAP_UPDATE' ;
mnemonic(?MAP_DELETE) -> 'MAP_DELETE' ;
mnemonic(?MAP_MEMBER) -> 'MAP_MEMBER' ;
mnemonic(?MAP_FROM_LIST) -> 'MAP_FROM_LIST' ;
mnemonic(?NIL) -> 'NIL' ;
mnemonic(?IS_NIL) -> 'IS_NIL' ;
mnemonic(?CONS) -> 'CONS' ;
mnemonic(?HD) -> 'HD' ;
mnemonic(?TL) -> 'TL' ;
mnemonic(?LENGTH) -> 'LENGTH' ;
mnemonic(?STR_EQ) -> 'STR_EQ' ;
mnemonic(?STR_JOIN) -> 'STR_JOIN' ;
mnemonic(?ADDR_TO_STR) -> 'ADDR_TO_STR' ;
mnemonic(?STR_REVERSE) -> 'STR_REVERSE' ;
mnemonic(?INT_TO_ADDR) -> 'INT_TO_ADDR' ;
mnemonic(?VARIANT) -> 'VARIANT' ;
mnemonic(?VARIANT_TEST) -> 'VARIANT_TEST' ;
mnemonic(?VARIANT_ELEMENT) -> 'VARIANT_ELEMENT' ;
mnemonic(?BITS_NONE) -> 'BITS_NONE' ;
mnemonic(?BITS_NONEA) -> 'BITS_NONEA' ;
mnemonic(?BITS_ALL) -> 'BITS_ALL' ;
mnemonic(?BITS_ALLA) -> 'BITS_ALLA' ;
mnemonic(?BITS_SET) -> 'BITS_SET' ;
mnemonic(?BITS_CLEAR) -> 'BITS_CLEAR' ;
mnemonic(?BITS_TEST) -> 'BITS_TEST' ;
mnemonic(?BITS_SUM) -> 'BITS_SUM' ;
mnemonic(?BITS_OR) -> 'BITS_OR' ;
mnemonic(?BITS_AND) -> 'BITS_AND' ;
mnemonic(?BITS_DIFF) -> 'BITS_DIFF' ;
mnemonic(?ADDRESS) -> 'ADDRESS' ;
mnemonic(?BALANCE) -> 'BALANCE' ;
mnemonic(?ORIGIN) -> 'ORIGIN' ;
mnemonic(?CALLER) -> 'CALLER' ;
mnemonic(?GASPRICE) -> 'GASPRICE' ;
mnemonic(?BLOCKHASH) -> 'BLOCKHASH' ;
mnemonic(?BENEFICIARY) -> 'BENEFICIARY' ;
mnemonic(?TIMESTAMP) -> 'TIMESTAMP' ;
mnemonic(?NUMBER) -> 'NUMBER' ;
mnemonic(?DIFFICULTY) -> 'DIFFICULTY' ;
mnemonic(?GASLIMIT) -> 'GASLIMIT' ;
mnemonic(?GAS) -> 'GAS' ;
mnemonic(?LOG0) -> 'LOG0' ;
mnemonic(?LOG1) -> 'LOG1' ;
mnemonic(?LOG2) -> 'LOG2' ;
mnemonic(?LOG3) -> 'LOG3' ;
mnemonic(?LOG4) -> 'LOG4' ;
mnemonic(?ABORT) -> 'ABORT' ;
mnemonic(?EXIT) -> 'EXIT' ;
mnemonic(?DEACTIVATE) -> 'DEACTIVATE' ;
mnemonic(?INC) -> 'INC' ;
mnemonic(?DEC) -> 'DEC' ;
mnemonic(?INCA) -> 'INCA' ;
mnemonic(?DECA) -> 'DECA' ;
mnemonic(?INT_TO_STR) -> 'INT_TO_STR' ;
mnemonic(?SPEND) -> 'SPEND' ;
mnemonic(?ORACLE_REGISTER) -> 'ORACLE_REGISTER' ;
mnemonic(?ORACLE_QUERY) -> 'ORACLE_QUERY' ;
mnemonic(?ORACLE_RESPOND) -> 'ORACLE_RESPOND' ;
mnemonic(?ORACLE_EXTEND) -> 'ORACLE_EXTEND' ;
mnemonic(?ORACLE_GET_ANSWER) -> 'ORACLE_GET_ANSWER' ;
mnemonic(?ORACLE_GET_QUESTION) -> 'ORACLE_GET_QUESTION' ;
mnemonic(?ORACLE_QUERY_FEE) -> 'ORACLE_QUERY_FEE' ;
mnemonic(?AENS_RESOLVE) -> 'AENS_RESOLVE' ;
mnemonic(?AENS_PRECLAIM) -> 'AENS_PRECLAIM' ;
mnemonic(?AENS_CLAIM) -> 'AENS_CLAIM' ;
mnemonic(?AENS_UPDATE) -> 'AENS_UPDATE' ;
mnemonic(?AENS_TRANSFER) -> 'AENS_TRANSFER' ;
mnemonic(?AENS_REVOKE) -> 'AENS_REVOKE' ;
mnemonic(?ECVERIFY) -> 'ECVERIFY' ;
mnemonic(?SHA3) -> 'SHA3' ;
mnemonic(?SHA256) -> 'SHA256' ;
mnemonic(?BLAKE2B) -> 'BLAKE2B' ;
mnemonic(?RETURNR) -> 'RETURNR' ;
mnemonic(?MAP_LOOKUPD) -> 'MAP_LOOKUPD' ;
mnemonic(?SWITCH_V2) -> 'SWITCH_V2' ;
mnemonic(?SWITCH_V3) -> 'SWITCH_V3' ;
mnemonic(?SWITCH_VN) -> 'SWITCH_VN' ;
mnemonic(?BITS_ALL_N) -> 'BITS_ALL_N' ;
mnemonic(?FUNCTION) -> 'FUNCTION' ;
mnemonic(?EXTEND) -> 'EXTEND'.
m_to_op('NOP') -> ?NOP ;
m_to_op('RETURN') -> ?RETURN ;
m_to_op('CALL') -> ?CALL ;
m_to_op('CALL_R') -> ?CALL_R ;
m_to_op('CALL_T') -> ?CALL_T ;
m_to_op('CALL_TR') -> ?CALL_TR ;
m_to_op('JUMP') -> ?JUMP ;
m_to_op('JUMPIF') -> ?JUMPIF ;
m_to_op('PUSH') -> ?PUSH ;
m_to_op('DUP') -> ?DUP ;
m_to_op('DUPA') -> ?DUPA ;
m_to_op('POP') -> ?POP ;
m_to_op('STORE') -> ?STORE ;
m_to_op('ADD') -> ?ADD ;
m_to_op('MUL') -> ?MUL ;
m_to_op('SUB') -> ?SUB ;
m_to_op('DIV') -> ?DIV ;
m_to_op('MOD') -> ?MOD ;
m_to_op('POW') -> ?POW ;
m_to_op('LT') -> ?LT ;
m_to_op('GT') -> ?GT ;
m_to_op('EQ') -> ?EQ ;
m_to_op('ELT') -> ?ELT ;
m_to_op('EGT') -> ?EGT ;
m_to_op('NEQ') -> ?NEQ ;
m_to_op('AND') -> ?AND ;
m_to_op('OR') -> ?OR ;
m_to_op('NOT') -> ?NOT ;
m_to_op('TUPLE') -> ?TUPLE ;
m_to_op('ELEMENT') -> ?ELEMENT ;
m_to_op('MAP_EMPTY') -> ?MAP_EMPTY ;
m_to_op('MAP_LOOKUP') -> ?MAP_LOOKUP ;
m_to_op('MAP_UPDATE') -> ?MAP_UPDATE ;
m_to_op('MAP_DELETE') -> ?MAP_DELETE ;
m_to_op('MAP_MEMBER') -> ?MAP_MEMBER ;
m_to_op('MAP_FROM_LIST') -> ?MAP_FROM_LIST ;
m_to_op('NIL') -> ?NIL ;
m_to_op('IS_NIL') -> ?IS_NIL ;
m_to_op('CONS') -> ?CONS ;
m_to_op('HD') -> ?HD ;
m_to_op('TL') -> ?TL ;
m_to_op('LENGTH') -> ?LENGTH ;
m_to_op('STR_EQ') -> ?STR_EQ ;
m_to_op('STR_JOIN') -> ?STR_JOIN ;
m_to_op('ADDR_TO_STR') -> ?ADDR_TO_STR ;
m_to_op('STR_REVERSE') -> ?STR_REVERSE ;
m_to_op('INT_TO_ADDR') -> ?INT_TO_ADDR ;
m_to_op('VARIANT') -> ?VARIANT ;
m_to_op('VARIANT_TEST') -> ?VARIANT_TEST ;
m_to_op('VARIANT_ELEMENT') -> ?VARIANT_ELEMENT ;
m_to_op('BITS_NONEA') -> ?BITS_NONEA ;
m_to_op('BITS_ALL') -> ?BITS_ALL ;
m_to_op('BITS_ALLA') -> ?BITS_ALLA ;
m_to_op('BITS_SET') -> ?BITS_SET ;
m_to_op('BITS_CLEAR') -> ?BITS_CLEAR ;
m_to_op('BITS_TEST') -> ?BITS_TEST ;
m_to_op('BITS_SUM') -> ?BITS_SUM ;
m_to_op('BITS_OR') -> ?BITS_OR ;
m_to_op('BITS_AND') -> ?BITS_AND ;
m_to_op('BITS_DIFF') -> ?BITS_DIFF ;
m_to_op('ADDRESS') -> ?ADDRESS ;
m_to_op('BALANCE') -> ?BALANCE ;
m_to_op('ORIGIN') -> ?ORIGIN ;
m_to_op('CALLER') -> ?CALLER ;
m_to_op('GASPRICE') -> ?GASPRICE ;
m_to_op('BLOCKHASH') -> ?BLOCKHASH ;
m_to_op('BENEFICIARY') -> ?BENEFICIARY ;
m_to_op('TIMESTAMP') -> ?TIMESTAMP ;
m_to_op('NUMBER') -> ?NUMBER ;
m_to_op('DIFFICULTY') -> ?DIFFICULTY ;
m_to_op('GASLIMIT') -> ?GASLIMIT ;
m_to_op('GAS') -> ?GAS ;
m_to_op('LOG0') -> ?LOG0 ;
m_to_op('LOG1') -> ?LOG1 ;
m_to_op('LOG2') -> ?LOG2 ;
m_to_op('LOG3') -> ?LOG3 ;
m_to_op('LOG4') -> ?LOG4 ;
m_to_op('ABORT') -> ?ABORT ;
m_to_op('EXIT') -> ?EXIT ;
m_to_op('DEACTIVATE') -> ?DEACTIVATE ;
m_to_op('INC') -> ?INC ;
m_to_op('DEC') -> ?DEC ;
m_to_op('INCA') -> ?INCA ;
m_to_op('DECA') -> ?DECA ;
m_to_op('INT_TO_STR') -> ?INT_TO_STR ;
m_to_op('SPEND') -> ?SPEND ;
m_to_op('ORACLE_REGISTER') -> ?ORACLE_REGISTER ;
m_to_op('ORACLE_QUERY') -> ?ORACLE_QUERY ;
m_to_op('ORACLE_RESPOND') -> ?ORACLE_RESPOND ;
m_to_op('ORACLE_EXTEND') -> ?ORACLE_EXTEND ;
m_to_op('ORACLE_GET_ANSWER') -> ?ORACLE_GET_ANSWER ;
m_to_op('ORACLE_GET_QUESTION') -> ?ORACLE_GET_QUESTION ;
m_to_op('ORACLE_QUERY_FEE') -> ?ORACLE_QUERY_FEE ;
m_to_op('AENS_RESOLVE') -> ?AENS_RESOLVE ;
m_to_op('AENS_PRECLAIM') -> ?AENS_PRECLAIM ;
m_to_op('AENS_CLAIM') -> ?AENS_CLAIM ;
m_to_op('AENS_UPDATE') -> ?AENS_UPDATE ;
m_to_op('AENS_TRANSFER') -> ?AENS_TRANSFER ;
m_to_op('AENS_REVOKE') -> ?AENS_REVOKE ;
m_to_op('ECVERIFY') -> ?ECVERIFY ;
m_to_op('SHA3') -> ?SHA3 ;
m_to_op('SHA256') -> ?SHA256 ;
m_to_op('BLAKE2B') -> ?BLAKE2B ;
m_to_op('RETURNR') -> ?RETURNR ;
m_to_op('MAP_LOOKUPD') -> ?MAP_LOOKUPD ;
m_to_op('SWITCH_V2') -> ?SWITCH_V2 ;
m_to_op('SWITCH_V3') -> ?SWITCH_V3 ;
m_to_op('SWITCH_VN') -> ?SWITCH_VN ;
m_to_op('FUNCTION') -> ?FUNCTION ;
m_to_op('EXTEND') -> ?EXTEND.
args(?NOP) -> 0;
args(?RETURN) -> 0;
args(?INCA) -> 0;
args(?DECA) -> 0;
args(?DUPA) -> 0;
args(?BITS_NONEA) -> 0;
args(?BITS_ALLA) -> 0;
args(?INC) -> 1;
args(?DEC) -> 1;
args(?RETURNR) -> 1;
args(?PUSH) -> 1;
args(?JUMP) -> 1;
args(?CALL) -> 1;
args(?CALL_T) -> 1;
args(?TUPLE) -> 1;
args(?MAP_EMPTY) -> 1;
args(?DUP) -> 1;
args(?POP) -> 1;
args(?NIL) -> 1;
args(?BITS_NONE) -> 1;
args(?BITS_ALL) -> 1;
args(?ADDRESS) -> 1;
args(?BALANCE) -> 1;
args(?ORIGIN) -> 1;
args(?CALLER) -> 1;
args(?GASPRICE) -> 1;
args(?BLOCKHASH) -> 1;
args(?BENEFICIARY) -> 1;
args(?TIMESTAMP) -> 1;
args(?NUMBER) -> 1;
args(?DIFFICULTY)-> 1;
args(?GASLIMIT) -> 1;
args(?GAS) -> 1;
args(?ABORT) -> 1;
args(?EXIT) -> 1;
args(?JUMPIF) -> 2;
args(?CALL_R) -> 2;
args(?CALL_TR) -> 2;
args(?HD) -> 2;
args(?TL) -> 2;
args(?NOT) -> 2;
args(?STORE) -> 2;
args(?LENGTH) -> 2;
args(?IS_NIL) -> 2;
args(?BITS_SUM) -> 2;
args(?BITS_ALL_N) -> 2;
args(?ADDR_TO_STR) -> 2;
args(?STR_REVERSE) -> 2;
args(?INT_TO_ADDR) -> 2;
args(?MAP_FROM_LIST) -> 2;
args(?ADD) -> 3;
args(?SUB) -> 3;
args(?MUL) -> 3;
args(?DIV) -> 3;
args(?MOD) -> 3;
args(?POW) -> 3;
args(?AND) -> 3;
args(?OR) -> 3;
args(?LT) -> 3;
args(?GT) -> 3;
args(?EGT) -> 3;
args(?ELT) -> 3;
args(?EQ) -> 3;
args(?NEQ) -> 3;
args(?CONS) -> 3;
args(?STR_EQ) -> 3;
args(?STR_JOIN) -> 3;
args(?MAP_MEMBER) -> 3;
args(?MAP_LOOKUP) -> 3;
args(?MAP_DELETE) -> 3;
args(?BITS_OR) -> 3;
args(?BITS_AND) -> 3;
args(?BITS_SET) -> 3;
args(?BITS_DIFF) -> 3;
args(?BITS_TEST) -> 3;
args(?BITS_CLEAR) -> 3;
args(?VARIANT_TEST) -> 3;
args(?VARIANT_ELEMENT) -> 3;
args(?INT_TO_STR) -> 3;
args(?SWITCH_V2) -> 3;
args(?SWITCH_V3) -> 4;
args(?ELEMENT) -> 4;
args(?VARIANT) -> 4;
args(?MAP_UPDATE) -> 4;
args(?MAP_LOOKUPD) -> 4;
args(?SWITCH_VN) -> 2;
args(_) -> 0. %% TODO do not allow this
end_bb(?RETURN) -> true;
end_bb(?RETURNR) -> true;
end_bb(?JUMP) -> true;
end_bb(?JUMPIF) -> true;
end_bb(?CALL) -> true;
end_bb(?CALL_T) -> true;
end_bb(?CALL_R) -> true;
end_bb(?CALL_TR) -> true;
end_bb(?SWITCH_V2) -> true;
end_bb(?SWITCH_V3) -> true;
end_bb(?SWITCH_VN) -> true;
end_bb(?ABORT) -> true;
end_bb(?EXIT) -> true;
end_bb(_) -> false.