From c85af9e7f3bc39152c3d0177a28351301c5c1032 Mon Sep 17 00:00:00 2001 From: Erik Stenman Date: Tue, 26 Feb 2019 22:51:33 +0100 Subject: [PATCH 1/8] Generate code for fate ops from spec. --- src/aeb_fate_asm.erl | 11 +- src/aeb_fate_code.erl | 140 ++++++++++++--- src/aeb_fate_data.erl | 31 +++- src/aeb_fate_generate_ops.erl | 329 ++++++++++++++++++++++++++++++++++ 4 files changed, 474 insertions(+), 37 deletions(-) create mode 100644 src/aeb_fate_generate_ops.erl diff --git a/src/aeb_fate_asm.erl b/src/aeb_fate_asm.erl index 1ea0bcb..3c163e4 100644 --- a/src/aeb_fate_asm.erl +++ b/src/aeb_fate_asm.erl @@ -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_date:fate_type_type()) -> [byte()]. serialize_type(integer) -> [0]; serialize_type(boolean) -> [1]; serialize_type({list, T}) -> [2 | serialize_type(T)]; diff --git a/src/aeb_fate_code.erl b/src/aeb_fate_code.erl index 26c881a..68bd94a 100644 --- a/src/aeb_fate_code.erl +++ b/src/aeb_fate_code.erl @@ -1,5 +1,76 @@ +%% Provide constructor functuions for Fate instructions. +%% Provide types and documentation for Fate instructions. + + -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 , return/1 , call/1 @@ -10,8 +81,7 @@ , jumpif/2 , switch/3 , switch/4 - , switch/5 - , switch/6 + , switch_n/2 , push/1 , inc/0 , inc/1 @@ -76,64 +146,80 @@ -define(i(__X__), {immediate, __X__ }). +-spec return() -> fate_return(). return() -> 'RETURN'. +-spec return(fate_arg()) -> fate_returnr(). return(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_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_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_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)}. -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)}. -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)}. -switch(Arg, BB1, BB2) when is_integer(BB1), - is_integer(BB2) -> +-spec switch(fate_arg(), + 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(Arg, BB1, BB2, BB3) when is_integer(BB1), - is_integer(BB2), - is_integer(BB3) -> +-spec switch(fate_arg(), + aeb_fate_data:fate_integer(), + 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(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)}. +-spec switch_n(fate_arg(), + [aeb_fate_data:fate_integer()]) + -> fate_switch_vn(). +switch_n(Arg, BBS) when is_list(BBS) -> + N = length(BBS), + {'SWITCH_VN', Arg, ?i(N), [?i(BB) || BB <- BBS]}. +-spec push(fate_arg()) -> fate_push(). push(Arg) -> {'PUSH', Arg}. +-spec inc() -> fate_inca(). inc() -> 'INCA'. +-spec inc(fate_arg()) -> fate_inc(). inc(Arg) -> {'INC', Arg}. +-spec dec() -> fate_deca(). dec() -> 'DECA'. +-spec dec(fate_arg()) -> fate_dec(). dec(Arg) -> {'DEC', Arg}. @@ -182,7 +268,7 @@ or_op(Dest, Left, Right) -> not_op(Dest, Arg) -> {'NOT', Dest, Arg}. -tuple(Size) when is_integer(Size) -> +tuple(Size) when ?IS_FATE_INTEGER(Size) -> {'TUPLE', ?i(Size)}. element_op(Type, Dest, N, T) -> @@ -290,7 +376,7 @@ bits_diff(To, Bits, Bit) -> dup() -> 'DUPA'. -dup(N) when is_integer(N) -> +dup(N) when ?IS_FATE_INTEGER(N) -> {'DUP', ?i(N)}. pop() -> diff --git a/src/aeb_fate_data.erl b/src/aeb_fate_data.erl index 243b204..f0a6898 100644 --- a/src/aeb_fate_data.erl +++ b/src/aeb_fate_data.erl @@ -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,7 +129,6 @@ 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) -> "[]"; diff --git a/src/aeb_fate_generate_ops.erl b/src/aeb_fate_generate_ops.erl new file mode 100644 index 0000000..259da48 --- /dev/null +++ b/src/aeb_fate_generate_ops.erl @@ -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()". + -- 2.30.2 From ab150ce7f89afb6baf19c0b3518b74fcaf5a488a Mon Sep 17 00:00:00 2001 From: Erik Stenman Date: Wed, 27 Feb 2019 11:55:53 +0100 Subject: [PATCH 2/8] Generate the code from the makefile. Remove generated files. --- .circleci/config.yml | 2 +- .gitignore | 3 + Makefile | 16 +- include/aeb_fate_opcodes.hrl | 121 ----------- src/aeb_fate_code.erl | 389 ---------------------------------- src/aeb_fate_generate_ops.erl | 86 +++++--- src/aeb_fate_opcodes.erl | 363 ------------------------------- 7 files changed, 69 insertions(+), 911 deletions(-) delete mode 100644 include/aeb_fate_opcodes.hrl delete mode 100644 src/aeb_fate_code.erl delete mode 100644 src/aeb_fate_opcodes.erl diff --git a/.circleci/config.yml b/.circleci/config.yml index e34c31c..c1b8283 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,7 +19,7 @@ jobs: - dialyzer-cache-v1- - run: name: Build - command: rebar3 compile + command: make - run: name: Static Analysis command: rebar3 dialyzer diff --git a/.gitignore b/.gitignore index 4ad6576..385e93a 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ aeb_asm_scan.erl aeb_fate_asm_scan.erl _build/ aefateasm +include/aeb_fate_opcodes.hrl +src/aeb_fate_code.erl +src/aeb_fate_opcodes.erl diff --git a/Makefile b/Makefile index 1d04708..f4e9034 100644 --- a/Makefile +++ b/Makefile @@ -4,17 +4,29 @@ REBAR ?= rebar3 all: local -local: +local: src/aeb_fate_opcodes.erl src/aeb_fate_code.erl include/aeb_fate_opcodes.hrl @$(REBAR) as local release -console: +console: src/aeb_fate_opcodes.erl src/aeb_fate_code.erl include/aeb_fate_opcodes.hrl @$(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 distclean: clean @rm -rf _build/ 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: ebin/aeb_fate_generate_ops.beam + erl -pa ebin/ -noshell -s aeb_fate_generate_ops gen_and_halt src/ include/ + +ebin: + mkdir ebin diff --git a/include/aeb_fate_opcodes.hrl b/include/aeb_fate_opcodes.hrl deleted file mode 100644 index 90f5b6a..0000000 --- a/include/aeb_fate_opcodes.hrl +++ /dev/null @@ -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}). - diff --git a/src/aeb_fate_code.erl b/src/aeb_fate_code.erl deleted file mode 100644 index 68bd94a..0000000 --- a/src/aeb_fate_code.erl +++ /dev/null @@ -1,389 +0,0 @@ -%% Provide constructor functuions for Fate instructions. -%% Provide types and documentation for Fate instructions. - - --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 - , return/1 - , call/1 - , call_t/1 - , call_r/2 - , call_tr/2 - , jump/1 - , jumpif/2 - , switch/3 - , switch/4 - , switch_n/2 - , 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__ }). - --spec return() -> fate_return(). -return() -> - 'RETURN'. - --spec return(fate_arg()) -> fate_returnr(). -return(Arg) -> - {'RETURNR', Arg}. - --spec call(aeb_fate_data:fate_string()) -> fate_call(). -call(Function) when ?IS_FATE_STRING(Function)-> - {'CALL', ?i(Function) }. - --spec call_t(aeb_fate_data:fate_string()) -> fate_call_t(). -call_t(Function) when ?IS_FATE_STRING(Function) -> - {'CALL_T', ?i(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)}. - --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)}. - --spec jump(aeb_fate_data:fate_integer()) -> fate_jump(). -jump(BB) when ?IS_FATE_INTEGER(BB) -> - {'JUMP', ?i(BB)}. - --spec jumpif(fate_arg(), aeb_fate_data:fate_integer()) -> fate_jumpif(). -jumpif(Arg, BB) when ?IS_FATE_INTEGER(BB) -> - {'JUMPIF', Arg, ?i(BB)}. - --spec switch(fate_arg(), - 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)}. - --spec switch(fate_arg(), - aeb_fate_data:fate_integer(), - 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)}. - --spec switch_n(fate_arg(), - [aeb_fate_data:fate_integer()]) - -> fate_switch_vn(). -switch_n(Arg, BBS) when is_list(BBS) -> - N = length(BBS), - {'SWITCH_VN', Arg, ?i(N), [?i(BB) || BB <- BBS]}. - --spec push(fate_arg()) -> fate_push(). -push(Arg) -> - {'PUSH', Arg}. - --spec inc() -> fate_inca(). -inc() -> - 'INCA'. - --spec inc(fate_arg()) -> fate_inc(). -inc(Arg) -> - {'INC', Arg}. - --spec dec() -> fate_deca(). -dec() -> - 'DECA'. - --spec dec(fate_arg()) -> fate_dec(). -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_FATE_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_FATE_INTEGER(N) -> - {'DUP', ?i(N)}. - -pop() -> - 'POP'. - -store(Var, What) -> - {'STORE', Var, What}. - -nop() -> - 'NOP'. diff --git a/src/aeb_fate_generate_ops.erl b/src/aeb_fate_generate_ops.erl index 259da48..0fc740c 100644 --- a/src/aeb_fate_generate_ops.erl +++ b/src/aeb_fate_generate_ops.erl @@ -1,34 +1,33 @@ - - -module(aeb_fate_generate_ops). --export([generate/0]). +-export([ gen_and_halt/1 + , 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()"). +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 = "aeb_new_fate_opcodes.hrl", + %% io:format("ops: ~p\n", [Ops]), + HrlFile = Include ++ "aeb_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). + generate_opcodes_ops(aeb_fate_opcodes, HrlFile, Src, Ops), + generate_code_ops(aeb_fate_code, Src, 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."} + [ { 'NOP', 16#f0, 0, false, 1, atomic, nop, "The no op. does nothing."} + , { 'RETURN', 16#00, 0, true, 2, atomic, return, "Return from function call pop stack to arg0."} + , { 'RETURNR', 16#01, 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_T', 16#04, 1, true, 4, [is], call_t, "Tail call to given 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."} @@ -56,20 +55,21 @@ ops_defs() -> , { '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"} + , { 'ELEMENT', 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."} + , { 'MAP_FROM_LIST',16#27, 2, false, 3, [a, a], map_from_list, "Arg0 := make a map from (key, value) list in 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."} @@ -78,7 +78,7 @@ ops_defs() -> , {'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."} + , {'VARIANT_ELEMNT',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."} @@ -94,6 +94,21 @@ ops_defs() -> , {'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."} + %% TODO: Check the documentation and update it. + , {'ADDRESS', 16#3f, 1, false, 3, [a], address, "Arg0 := The current contract address."} + , {'BALANCE', 16#3f, 1, false, 3, [a], balance, "Arg0 := The current contract address."} + , {'ORIGIN', 16#40, 1, false, 3, [a], origin, "Arg0 := Address of contract called by the call transaction."} + , {'CALLER', 16#41, 1, false, 3, [a], caller, "Arg0 := The address that signed the call transaction."} + , {'GASPRICE', 16#42, 1, false, 3, [a], gasprice, "Arg0 := The current gas price."} + , {'BLOCKHASH', 16#43, 1, false, 3, [a], blockhash, "Arg0 := The current blockhash."} %% TODO: Do we support has at height? + , {'BENEFICIARY',16#44, 1, false, 3, [a], beneficiary, "Arg0 := The address of the current beneficiary."} + , {'TIMESTAMP', 16#45, 1, false, 3, [a], timestamp, "Arg0 := The current timestamp. Unrelaiable, don't use for anything."} + , {'NUMBER', 16#46, 1, false, 3, [a], number, "Arg0 := The block height."} + , {'DIFFICULTY',16#47, 1, false, 3, [a], difficulty, "Arg0 := The current difficulty."} + , {'GASLIMIT', 16#48, 1, false, 3, [a], gaslimit, "Arg0 := The current gaslimit."} + , {'GAS', 16#49, 1, false, 3, [a], gas, "Arg0 := The amount of gas left."} + , {'ABORT', 16#4f, 1, false, 3, [a], abort, "Abort execution (dont use all gas) with error message in Arg0."} + , {'EXIT', 16#4e, 1, false, 3, [a], exit, "Abort execution (use upp all gas) with error message in Arg0."} ]. @@ -102,10 +117,13 @@ generate_header_file(Filename, Ops) -> 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, Ops) -> - Filename = atom_to_list(Modulename) ++ ".erl", +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]), @@ -135,8 +153,8 @@ generate_opcodes_ops(Modulename, HrlFile, Ops) -> file:close(File). -generate_code_ops(Modulename, Ops) -> - Filename = atom_to_list(Modulename) ++ ".erl", +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]), @@ -163,7 +181,6 @@ generate_code_ops(Modulename, Ops) -> " | 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]), @@ -172,7 +189,6 @@ generate_code_ops(Modulename, Ops) -> io:format(File, "~s\n", [Constructors]), io:format(File, "foo() -> \"A temp hack.\".\n", []), - file:close(File). @@ -222,7 +238,7 @@ gen_arg_type_specs([t | Args]) -> "aeb_fate_data:fate_type_type(), " ++ gen_arg_ gen_arg_names(_, []) -> []; gen_arg_names(N, [_]) -> io_lib:format("Arg~w", [N]); -gen_arg_names(N, [_|Args]) -> +gen_arg_names(N, [_|Args]) -> io_lib:format("Arg~w, ", [N]) ++ gen_arg_names(N+1, Args). gen_arg_uses(_, []) -> @@ -232,15 +248,15 @@ 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]) -> +gen_arg_uses(N, [a | Args]) -> io_lib:format("Arg~w, ", [N]) ++ gen_arg_uses(N+1, Args); -gen_arg_uses(N, [is | 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]) -> +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]) -> +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]) -> +gen_arg_uses(N, [t | Args]) -> io_lib:format("Arg~w, ", [N]) ++ gen_arg_uses(N+1, Args). @@ -248,7 +264,7 @@ 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" + "-include_lib(\"aebytecode/" ++ HrlFile ++"\").\n\n" "%%====================================================================\n" "%% API\n" "%%====================================================================\n", diff --git a/src/aeb_fate_opcodes.erl b/src/aeb_fate_opcodes.erl deleted file mode 100644 index 84d93f7..0000000 --- a/src/aeb_fate_opcodes.erl +++ /dev/null @@ -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. -- 2.30.2 From c624f4956c424987b9f588b8d9be7fb60563ab47 Mon Sep 17 00:00:00 2001 From: Erik Stenman Date: Wed, 27 Feb 2019 15:25:57 +0100 Subject: [PATCH 3/8] Test targets and cleanup. --- .circleci/config.yml | 6 +- Makefile | 9 ++ src/aeb_fate_asm.erl | 2 +- src/aeb_fate_generate_ops.erl | 176 +++++++++++++++++----------------- 4 files changed, 101 insertions(+), 92 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c1b8283..2d09292 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -22,13 +22,13 @@ jobs: 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 ct - save_cache: key: dialyzer-cache-v1-{{ .Branch }}-{{ .Revision }} paths: diff --git a/Makefile b/Makefile index f4e9034..fd94da3 100644 --- a/Makefile +++ b/Makefile @@ -16,12 +16,21 @@ clean: 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/ +euint: 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 $@) $< diff --git a/src/aeb_fate_asm.erl b/src/aeb_fate_asm.erl index 3c163e4..5e320ef 100644 --- a/src/aeb_fate_asm.erl +++ b/src/aeb_fate_asm.erl @@ -820,7 +820,7 @@ to_list_of_types(Tokens) -> {[Type], Rest} end. --spec serialize_type(aeb_fate_date:fate_type_type()) -> [byte()]. +-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)]; diff --git a/src/aeb_fate_generate_ops.erl b/src/aeb_fate_generate_ops.erl index 0fc740c..486fc54 100644 --- a/src/aeb_fate_generate_ops.erl +++ b/src/aeb_fate_generate_ops.erl @@ -19,96 +19,96 @@ generate(Src, Include) -> generate_opcodes_ops(aeb_fate_opcodes, HrlFile, Src, Ops), generate_code_ops(aeb_fate_code, Src, Ops). - +%% TODO: Some real gas numbers... ops_defs() -> - %% Opname, Opcode, args, end_bb, gas, format, Constructor, Documentation - [ { 'NOP', 16#f0, 0, false, 1, atomic, nop, "The no op. does nothing."} - , { 'RETURN', 16#00, 0, true, 2, atomic, return, "Return from function call pop stack to arg0."} - , { 'RETURNR', 16#01, 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_R', 16#03, 2, true, 8, [a, is], call_r, "Remote call to given contract and function."} - , { 'CALL_T', 16#04, 1, true, 4, [is], call_t, "Tail call to given 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."} - , { 'ELEMENT', 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."} - , { 'MAP_FROM_LIST',16#27, 2, false, 3, [a, a], map_from_list, "Arg0 := make a map from (key, value) list in 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."} + %% Opname, Opcode, args, end_bb, gas, format, Constructor, Documentation + [ { 'NOP', 16#f0, 0, false, 1, atomic, nop, "The no op. does nothing."} + , { 'RETURN', 16#00, 0, true, 2, atomic, return, "Return from function call pop stack to arg0."} + , { 'RETURNR', 16#01, 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_R', 16#03, 2, true, 8, [a,is], call_r, "Remote call to given contract and function."} + , { 'CALL_T', 16#04, 1, true, 4, [is], call_t, "Tail call to given 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."} + , { 'ELEMENT', 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."} + , { 'MAP_FROM_LIST',16#27, 2, false, 3, [a,a], map_from_list, "Arg0 := make a map from (key, value) list in 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."} + , {'ADDRESS', 16#3f, 1, false, 3, [a], address, "Arg0 := The current contract address."} + , {'BALANCE', 16#40, 1, false, 3, [a], balance, "Arg0 := The current contract address."} + , {'ORIGIN', 16#41, 1, false, 3, [a], origin, "Arg0 := Address of contract called by the call transaction."} + , {'CALLER', 16#42, 1, false, 3, [a], caller, "Arg0 := The address that signed the call transaction."} + , {'GASPRICE', 16#43, 1, false, 3, [a], gasprice, "Arg0 := The current gas price."} + , {'BLOCKHASH', 16#44, 1, false, 3, [a], blockhash, "Arg0 := The current blockhash."} %% TODO: Do we support has at height? + , {'BENEFICIARY', 16#45, 1, false, 3, [a], beneficiary, "Arg0 := The address of the current beneficiary."} + , {'TIMESTAMP', 16#46, 1, false, 3, [a], timestamp, "Arg0 := The current timestamp. Unrelaiable, don't use for anything."} + , {'NUMBER', 16#47, 1, false, 3, [a], number, "Arg0 := The block height."} + , {'DIFFICULTY', 16#48, 1, false, 3, [a], difficulty, "Arg0 := The current difficulty."} + , {'GASLIMIT', 16#49, 1, false, 3, [a], gaslimit, "Arg0 := The current gaslimit."} + , {'GAS', 16#4a, 1, false, 3, [a], gas, "Arg0 := The amount of gas left."} + , {'ABORT', 16#50, 1, false, 3, [a], abort, "Abort execution (dont use all gas) with error message in Arg0."} + , {'EXIT', 16#51, 1, false, 3, [a], exit, "Abort execution (use upp all gas) with error message in Arg0."} - , {'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_ELEMNT',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."} - %% TODO: Check the documentation and update it. - , {'ADDRESS', 16#3f, 1, false, 3, [a], address, "Arg0 := The current contract address."} - , {'BALANCE', 16#3f, 1, false, 3, [a], balance, "Arg0 := The current contract address."} - , {'ORIGIN', 16#40, 1, false, 3, [a], origin, "Arg0 := Address of contract called by the call transaction."} - , {'CALLER', 16#41, 1, false, 3, [a], caller, "Arg0 := The address that signed the call transaction."} - , {'GASPRICE', 16#42, 1, false, 3, [a], gasprice, "Arg0 := The current gas price."} - , {'BLOCKHASH', 16#43, 1, false, 3, [a], blockhash, "Arg0 := The current blockhash."} %% TODO: Do we support has at height? - , {'BENEFICIARY',16#44, 1, false, 3, [a], beneficiary, "Arg0 := The address of the current beneficiary."} - , {'TIMESTAMP', 16#45, 1, false, 3, [a], timestamp, "Arg0 := The current timestamp. Unrelaiable, don't use for anything."} - , {'NUMBER', 16#46, 1, false, 3, [a], number, "Arg0 := The block height."} - , {'DIFFICULTY',16#47, 1, false, 3, [a], difficulty, "Arg0 := The current difficulty."} - , {'GASLIMIT', 16#48, 1, false, 3, [a], gaslimit, "Arg0 := The current gaslimit."} - , {'GAS', 16#49, 1, false, 3, [a], gas, "Arg0 := The amount of gas left."} - , {'ABORT', 16#4f, 1, false, 3, [a], abort, "Abort execution (dont use all gas) with error message in Arg0."} - , {'EXIT', 16#4e, 1, false, 3, [a], exit, "Abort execution (use upp all gas) with error message in Arg0."} ]. -- 2.30.2 From 9411a131fc1e4b52d41aad48c9d58e28c06d34d2 Mon Sep 17 00:00:00 2001 From: Erik Stenman Date: Wed, 27 Feb 2019 15:28:11 +0100 Subject: [PATCH 4/8] Spell eunit the right way. --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index fd94da3..6153766 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ dialyzer: local distclean: clean @rm -rf _build/ -euint: local +eunit: local @$(REBAR) as local eunit test: local -- 2.30.2 From 268208ec9887d4008b206ae473e273f5cc9c3b96 Mon Sep 17 00:00:00 2001 From: Erik Stenman Date: Wed, 27 Feb 2019 15:36:48 +0100 Subject: [PATCH 5/8] Use test target for ci. --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2d09292..0c9ac9f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -28,7 +28,7 @@ jobs: command: make eunit - run: name: Common Tests - command: make ct + command: make test - save_cache: key: dialyzer-cache-v1-{{ .Branch }}-{{ .Revision }} paths: -- 2.30.2 From 161b5a610684c1cdde7f41bdacfdb264b27dc8a7 Mon Sep 17 00:00:00 2001 From: Erik Stenman Date: Wed, 27 Feb 2019 17:47:08 +0100 Subject: [PATCH 6/8] Renumber opcodes. Add primops. --- src/aeb_fate_generate_ops.erl | 201 +++++++++++++++++++--------------- 1 file changed, 115 insertions(+), 86 deletions(-) diff --git a/src/aeb_fate_generate_ops.erl b/src/aeb_fate_generate_ops.erl index 486fc54..3bb8a26 100644 --- a/src/aeb_fate_generate_ops.erl +++ b/src/aeb_fate_generate_ops.erl @@ -22,93 +22,122 @@ generate(Src, Include) -> %% TODO: Some real gas numbers... ops_defs() -> %% Opname, Opcode, args, end_bb, gas, format, Constructor, Documentation - [ { 'NOP', 16#f0, 0, false, 1, atomic, nop, "The no op. does nothing."} - , { 'RETURN', 16#00, 0, true, 2, atomic, return, "Return from function call pop stack to arg0."} - , { 'RETURNR', 16#01, 1, true, 2, [a], returnr, "Return from function call pop stack to arg0."} + [ { 'RETURN', 16#00, 0, true, 2, atomic, return, "Return from function call pop stack to arg0."} + , { 'RETURNR', 16#01, 1, true, 2, [a], returnr, "Return from function call copy Arg0 to arg0."} , { 'CALL', 16#02, 1, true, 4, [is], call, "Call given function with args on stack."} , { 'CALL_R', 16#03, 2, true, 8, [a,is], call_r, "Remote call to given contract and function."} , { 'CALL_T', 16#04, 1, true, 4, [is], call_t, "Tail call to given 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."} - , { 'ELEMENT', 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."} - , { 'MAP_FROM_LIST',16#27, 2, false, 3, [a,a], map_from_list, "Arg0 := make a map from (key, value) list in 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."} - , {'ADDRESS', 16#3f, 1, false, 3, [a], address, "Arg0 := The current contract address."} - , {'BALANCE', 16#40, 1, false, 3, [a], balance, "Arg0 := The current contract address."} - , {'ORIGIN', 16#41, 1, false, 3, [a], origin, "Arg0 := Address of contract called by the call transaction."} - , {'CALLER', 16#42, 1, false, 3, [a], caller, "Arg0 := The address that signed the call transaction."} - , {'GASPRICE', 16#43, 1, false, 3, [a], gasprice, "Arg0 := The current gas price."} - , {'BLOCKHASH', 16#44, 1, false, 3, [a], blockhash, "Arg0 := The current blockhash."} %% TODO: Do we support has at height? - , {'BENEFICIARY', 16#45, 1, false, 3, [a], beneficiary, "Arg0 := The address of the current beneficiary."} - , {'TIMESTAMP', 16#46, 1, false, 3, [a], timestamp, "Arg0 := The current timestamp. Unrelaiable, don't use for anything."} - , {'NUMBER', 16#47, 1, false, 3, [a], number, "Arg0 := The block height."} - , {'DIFFICULTY', 16#48, 1, false, 3, [a], difficulty, "Arg0 := The current difficulty."} - , {'GASLIMIT', 16#49, 1, false, 3, [a], gaslimit, "Arg0 := The current gaslimit."} - , {'GAS', 16#4a, 1, false, 3, [a], gas, "Arg0 := The amount of gas left."} - , {'ABORT', 16#50, 1, false, 3, [a], abort, "Abort execution (dont use all gas) with error message in Arg0."} - , {'EXIT', 16#51, 1, false, 3, [a], exit, "Abort execution (use upp all gas) with error message in Arg0."} + , { '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."} + , { 'NUMBER', 16#61, 1, false, 3, [a], number, "Arg0 := The block height."} + , { 'DIFFICULTY', 16#62, 1, false, 3, [a], difficulty, "Arg0 := The current difficulty."} + , { 'GASLIMIT', 16#63, 1, false, 3, [a], gaslimit, "Arg0 := The current gaslimit."} + , { 'GAS', 16#64, 1, false, 3, [a], gas, "Arg0 := The amount of gas left."} + , { 'LOG0', 16#65, 2, false, 3, [a,a], log, "Create a log message in the call object."} + , { 'LOG1', 16#66, 3, false, 3, [a,a,a], log, "Create a log message with one topic in the call object."} + , { 'LOG2', 16#67, 4, false, 3, [a,a,a,a], log, "Create a log message with two topics in the call object."} + , { 'LOG3', 16#68, 5, false, 3, [a,a,a,a,a], log, "Create a log message with three topics in the call object."} + , { 'LOG4', 16#69, 6, false, 3, [a,a,a,a,a,a], log, "Create a log message with four topics in the call object."} + , { 'DEACTIVATE', 16#6a, 0, false, 3, atomic, deactivate, "Mark the current contract for deactication."} + %% Transaction ops + , { 'SPEND', 16#6b, 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#6c, 6, false,3, [a,a,a,a,a,a], oracle_register, "Mark the current contract for deactication."} + %% TODO: + , { 'ORACLE_QUERY', 16#6d, 0, false,3, atomic, oracle_query, ""} + , { 'ORACLE_RESPOND', 16#6e, 0, false,3, atomic, oracle_respond, ""} + , { 'ORACLE_EXTEND', 16#6f, 0, false,3, atomic, oracle_extend, ""} + , { 'ORACLE_GET_ANSWER', 16#70, 0, false,3, atomic, oracle_get_answer, ""} + , { 'ORACLE_GET_QUESTION', 16#71, 0, false,3, atomic,oracle_get_question, ""} + , { 'ORACLE_QUERY_FEE', 16#72, 0, false,3, atomic, oracle_query_fee, ""} + , { 'AENS_RESOLVE', 16#73, 0, false,3, atomic, aens_resolve, ""} + , { 'AENS_PRECLAIM', 16#74, 0, false,3, atomic, aens_preclaim, ""} + , { 'AENS_CLAIM', 16#75, 0, false,3, atomic, aens_claim, ""} + , { 'AENS_UPDATE', 16#76, 0, false,3, atomic, aend_update, ""} + , { 'AENS_TRANSFER', 16#77, 0, false,3, atomic, aens_transfer, ""} + , { 'AENS_REVOKE', 16#78, 0, false,3, atomic, aens_revoke, ""} + , { 'ECVERIFY', 16#79, 0, false,3, atomic, ecverify, ""} + , { 'SHA3', 16#7a, 0, false,3, atomic, sha3, ""} + , { 'SHA256', 16#7b, 0, false,3, atomic, sha256, ""} + , { 'BLAKE2B', 16#7c, 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." ]. @@ -118,8 +147,8 @@ generate_header_file(Filename, 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"]), + ["-define('FUNCTION' , 16#fe).\n" + "-define('EXTEND' , 16#ff).\n\n"]), file:close(File). generate_opcodes_ops(Modulename, HrlFile, SrcDir, Ops) -> @@ -193,7 +222,7 @@ generate_code_ops(Modulename, SrcDir, Ops) -> file:close(File). gen_type(#{type_name := TypeName, type := Type}) -> - lists:flatten(io_lib:format("-type ~-25s :: ~s.\n", + lists:flatten(io_lib:format("-type ~-26s :: ~s.\n", [TypeName, Type])). gen_fate_code_type(#{type_name := TypeName}) -> @@ -302,7 +331,7 @@ prelude(Doc) -> gen_defines(#{opname := Name, opcode := OpCode}) -> - lists:flatten(io_lib:format("-define(~-17w, 16#~2.16.0b).\n", [Name, OpCode])). + lists:flatten(io_lib:format("-define(~-26w, 16#~2.16.0b).\n", [Name, OpCode])). gen([]) -> []; @@ -313,11 +342,11 @@ gen([{OpName, OpCode, Args, EndBB, Gas, FateFormat, Constructor, Doc} | Rest]) - Macro = "?" ++ Name, Type = case FateFormat of atomic -> io_lib:format("~w", [OpName]); - ArgTypes -> + 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 -- 2.30.2 From dd1a6a9c3d36762dcb979c15c53f4fe8dc70f734 Mon Sep 17 00:00:00 2001 From: Erik Stenman Date: Thu, 28 Feb 2019 07:55:51 +0100 Subject: [PATCH 7/8] Generate tokens in scanner from definitions. --- .gitignore | 1 + Makefile | 6 +- src/aeb_fate_asm_scan.template | 99 ++++++++++++++++ src/aeb_fate_asm_scan.xrl | 207 --------------------------------- src/aeb_fate_generate_ops.erl | 45 +++++-- 5 files changed, 139 insertions(+), 219 deletions(-) create mode 100644 src/aeb_fate_asm_scan.template delete mode 100644 src/aeb_fate_asm_scan.xrl diff --git a/.gitignore b/.gitignore index 385e93a..cccd365 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ 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 diff --git a/Makefile b/Makefile index 6153766..071e04c 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,10 @@ REBAR ?= rebar3 all: local -local: src/aeb_fate_opcodes.erl src/aeb_fate_code.erl include/aeb_fate_opcodes.hrl +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: src/aeb_fate_opcodes.erl src/aeb_fate_code.erl include/aeb_fate_opcodes.hrl +console: local @$(REBAR) as local shell clean: @@ -34,7 +34,7 @@ test: local 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: ebin/aeb_fate_generate_ops.beam +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: diff --git a/src/aeb_fate_asm_scan.template b/src/aeb_fate_asm_scan.template new file mode 100644 index 0000000..f894aa5 --- /dev/null +++ b/src/aeb_fate_asm_scan.template @@ -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), + <>. + +scan(S) -> + string(S). + +drop_prefix(C, [C|Rest]) -> + drop_prefix(C, Rest); +drop_prefix(_, Tail) -> Tail. diff --git a/src/aeb_fate_asm_scan.xrl b/src/aeb_fate_asm_scan.xrl deleted file mode 100644 index 6d10f56..0000000 --- a/src/aeb_fate_asm_scan.xrl +++ /dev/null @@ -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), - <>. - -scan(S) -> - string(S). - -drop_prefix(C, [C|Rest]) -> - drop_prefix(C, Rest); -drop_prefix(_, Tail) -> Tail. diff --git a/src/aeb_fate_generate_ops.erl b/src/aeb_fate_generate_ops.erl index 3bb8a26..925caf9 100644 --- a/src/aeb_fate_generate_ops.erl +++ b/src/aeb_fate_generate_ops.erl @@ -17,19 +17,20 @@ generate(Src, Include) -> 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_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."} - , { 'RETURNR', 16#01, 1, true, 2, [a], returnr, "Return from function call copy Arg0 to arg0."} - , { 'CALL', 16#02, 1, true, 4, [is], call, "Call given function with args on stack."} - , { 'CALL_R', 16#03, 2, true, 8, [a,is], call_r, "Remote call to given contract and function."} - , { 'CALL_T', 16#04, 1, true, 4, [is], call_t, "Tail call to given 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."} + [ { '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."} @@ -372,3 +373,29 @@ 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(<>, Tokens) -> + [B|insert_tokens_in_template(Rest, Tokens)]. + + + -- 2.30.2 From 8dd8e89c1ecbd830b729685c62fffb91998dbc3a Mon Sep 17 00:00:00 2001 From: Erik Stenman Date: Thu, 28 Feb 2019 08:13:26 +0100 Subject: [PATCH 8/8] Rename NUMBER op to GENERATION and add MICROBLOCK instruction. --- src/aeb_fate_generate_ops.erl | 57 ++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/src/aeb_fate_generate_ops.erl b/src/aeb_fate_generate_ops.erl index 925caf9..3eb7def 100644 --- a/src/aeb_fate_generate_ops.erl +++ b/src/aeb_fate_generate_ops.erl @@ -102,37 +102,38 @@ ops_defs() -> , { '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."} - , { 'NUMBER', 16#61, 1, false, 3, [a], number, "Arg0 := The block height."} - , { 'DIFFICULTY', 16#62, 1, false, 3, [a], difficulty, "Arg0 := The current difficulty."} - , { 'GASLIMIT', 16#63, 1, false, 3, [a], gaslimit, "Arg0 := The current gaslimit."} - , { 'GAS', 16#64, 1, false, 3, [a], gas, "Arg0 := The amount of gas left."} + , { '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#65, 2, false, 3, [a,a], log, "Create a log message in the call object."} - , { 'LOG1', 16#66, 3, false, 3, [a,a,a], log, "Create a log message with one topic in the call object."} - , { 'LOG2', 16#67, 4, false, 3, [a,a,a,a], log, "Create a log message with two topics in the call object."} - , { 'LOG3', 16#68, 5, false, 3, [a,a,a,a,a], log, "Create a log message with three topics in the call object."} - , { 'LOG4', 16#69, 6, false, 3, [a,a,a,a,a,a], log, "Create a log message with four topics in the call object."} - , { 'DEACTIVATE', 16#6a, 0, false, 3, atomic, deactivate, "Mark the current contract for deactication."} + , { '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#6b, 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#6c, 6, false,3, [a,a,a,a,a,a], oracle_register, "Mark the current contract for deactication."} + , { '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#6d, 0, false,3, atomic, oracle_query, ""} - , { 'ORACLE_RESPOND', 16#6e, 0, false,3, atomic, oracle_respond, ""} - , { 'ORACLE_EXTEND', 16#6f, 0, false,3, atomic, oracle_extend, ""} - , { 'ORACLE_GET_ANSWER', 16#70, 0, false,3, atomic, oracle_get_answer, ""} - , { 'ORACLE_GET_QUESTION', 16#71, 0, false,3, atomic,oracle_get_question, ""} - , { 'ORACLE_QUERY_FEE', 16#72, 0, false,3, atomic, oracle_query_fee, ""} - , { 'AENS_RESOLVE', 16#73, 0, false,3, atomic, aens_resolve, ""} - , { 'AENS_PRECLAIM', 16#74, 0, false,3, atomic, aens_preclaim, ""} - , { 'AENS_CLAIM', 16#75, 0, false,3, atomic, aens_claim, ""} - , { 'AENS_UPDATE', 16#76, 0, false,3, atomic, aend_update, ""} - , { 'AENS_TRANSFER', 16#77, 0, false,3, atomic, aens_transfer, ""} - , { 'AENS_REVOKE', 16#78, 0, false,3, atomic, aens_revoke, ""} - , { 'ECVERIFY', 16#79, 0, false,3, atomic, ecverify, ""} - , { 'SHA3', 16#7a, 0, false,3, atomic, sha3, ""} - , { 'SHA256', 16#7b, 0, false,3, atomic, sha256, ""} - , { 'BLAKE2B', 16#7c, 0, false,3, atomic, blake2b, ""} + , { '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."} -- 2.30.2