From 7b9c1b856be74b87deef83b1b847adce11a789b0 Mon Sep 17 00:00:00 2001 From: radrow Date: Tue, 8 Jun 2021 11:26:18 +0200 Subject: [PATCH 1/4] Upgrade doc generation --- src/aeb_fate_generate_docs.erl | 109 +++++++++++++++++++++++++++++++++ src/aeb_fate_generate_ops.erl | 50 +-------------- 2 files changed, 110 insertions(+), 49 deletions(-) create mode 100644 src/aeb_fate_generate_docs.erl diff --git a/src/aeb_fate_generate_docs.erl b/src/aeb_fate_generate_docs.erl new file mode 100644 index 0000000..e69a77c --- /dev/null +++ b/src/aeb_fate_generate_docs.erl @@ -0,0 +1,109 @@ +-module(aeb_fate_generate_docs). + +-export([generate_documentation/2, generate_documentation/3]). + +-export( + [ gen_protocol_opcodes_flags_and_gas/1 + , gen_protocol_description_of_operations/1 + ]). + +generate_documentation(Filename, Fields) -> + generate_documentation(Filename, Fields, fun(_) -> true end). +generate_documentation(Filename, Fields, Filter) when is_function(Filter, 1) -> + {ok, File} = file:open(Filename, [write]), + Instructions = + lists:flatten( + [gen_doc_for_op(Op, [F || F <- Fields]) + ++ "\n" || Op <- aeb_fate_generate_ops:get_ops(), Filter(Op)]), + Header = + lists:flatten( + "|" ++ [" " ++ header_name(F) ++ " |" || F <- Fields] ++ "\n" + ), + Separator = + lists:flatten( + "|" ++ [" " ++ ["-" || _ <- header_name(F)] ++ " |" || F <- Fields] ++ "\n" + ), + io:format(File, "~s~s~s\n", [Header, Separator, Instructions]), + file:close(File). + +header_name(opname) -> + "Name"; +header_name(opcode) -> + "Opcode"; +header_name(arity) -> + "Arity"; +header_name(end_bb) -> + "Ends basic block"; +header_name(in_auth) -> + "Allowed in auth"; +header_name(offchain) -> + "Allowed offchain"; +header_name(format) -> + "Args"; +header_name(doc) -> + "Description"; +header_name(gas) -> + "Gas cost"; +header_name(arg_types) -> + "Arg types"; +header_name(res_type) -> + "Res type". + +gen_doc_for_op(#{ opname := OpName + , opcode := OpCode + , arity := Arity + , end_bb := EndBB + , in_auth := InAuth + , offchain := AllowedOffchain + , format := FateFormat + , doc := Doc + , gas := Gas + , arg_types := ArgTypes + , res_type := ResType + }, Fields) -> + "| " ++ + string:join( + [ case Field of + opname -> io_lib:format("`~s`", [OpName]); + opcode -> io_lib:format("0x~.16b", [OpCode]); + arity -> io_lib:format("~p", [Arity]); + end_bb -> io_lib:format("~p", [EndBB]); + in_auth -> io_lib:format("~p", [InAuth]); + offchain -> io_lib:format("~p", [AllowedOffchain]); + format -> + case FateFormat of + [] -> ""; + _ -> lists:join( + " ", + [format_arg_doc(A) || + A <- + lists:zip(FateFormat, + lists:seq(0,length(FateFormat)-1))]) + end; + doc -> Doc; + gas -> io_lib:format("~p", [Gas]); + arg_types -> io_lib:format("~p", [ArgTypes]); + res_type -> io_lib:format("~p", [ResType]) + end + || Field <- Fields + ], + " | ") ++ " |". + +format_arg_doc({a, N}) -> io_lib:format("Arg~w", [N]); +format_arg_doc({is,_N}) -> "Identifier"; +format_arg_doc({ii,_N}) -> "Integer"; +format_arg_doc({li,_N}) -> "[Integers]"; +format_arg_doc({t,_N}) -> "Type". + + +%% --- protocol documentation --- + +gen_protocol_description_of_operations(Filename) -> + generate_documentation( + Filename, [opname, format, doc, arg_types, res_type] + ). + +gen_protocol_opcodes_flags_and_gas(Filename) -> + generate_documentation( + Filename, [opcode, opname, end_bb, in_auth, offchain, gas] + ). diff --git a/src/aeb_fate_generate_ops.erl b/src/aeb_fate_generate_ops.erl index 35e012e..b107ecc 100644 --- a/src/aeb_fate_generate_ops.erl +++ b/src/aeb_fate_generate_ops.erl @@ -2,7 +2,6 @@ -export([ gen_and_halt/1 , generate/0 - , generate_documentation/1 , get_ops/0 , test_asm_generator/1 ]). @@ -46,7 +45,7 @@ check_numbering(_, []) -> true. -define(GAS_IRIS(A, B), [{?IRIS_PROTOCOL_VSN, B}, {?LIMA_PROTOCOL_VSN, A}]). ops_defs() -> - %% Opname, Opcode, end_bb, in_auth offchain, gas, format, Constructor, ArgType, ResType, Documentation + %% Opname, Opcode, end_bb, in_auth,offchain, gas, format, Constructor, ArgType, ResType, Documentation [ { 'RETURN', 16#00, true, true, true, ?GAS(10), [], return, {}, any, "Return from function call, top of stack is return value . The type of the retun value has to match the return type of the function."} , { 'RETURNR', 16#01, true, true, true, ?GAS(10), [a], returnr, {any}, any, "Push Arg0 and return from function. The type of the retun value has to match the return type of the function."} , { 'CALL', 16#02, true, true, true, ?GAS(10), [a], call, {string}, any, "Call the function Arg0 with args on stack. The types of the arguments has to match the argument typs of the function."} @@ -778,50 +777,3 @@ gen_variant() -> 3 -> "(| 2 | 0 | ( " ++ imm_arg() ++ ", " ++ imm_arg() ++ " ) |)" end. - -%% TODO: add gas cost and end_bb/in_auth? -generate_documentation(Filename) -> - {ok, File} = file:open(Filename, [write]), - Instructions = lists:flatten([gen_doc(Op)++"\n" || Op <- get_ops()]), - io:format(File, - "### Operations\n\n" - "| OpCode | Name | Args | Description |\n" - "| --- | --- | --- | --- |\n" - "~s" - , [Instructions]), - io:format(File, "\n", []), - file:close(File). - -gen_doc(#{ opname := Name - , opcode := OpCode - , arity := _Arity - , end_bb := _EndBB - , format := FateFormat - , macro := _Macro - , type_name := _TypeName - , doc := Doc - , gas := _Gas - , type := _Type - , constructor := _Constructor - , constructor_type := _ConstructorType - }) -> - Arguments = - case FateFormat of - [] -> ""; - _ -> lists:join(" ", - [format_arg_doc(A) || - A <- - lists:zip(FateFormat, - lists:seq(0,length(FateFormat)-1))]) - end, - io_lib:format("| 0x~.16b | ~w | ~s | ~s |\n", - [ OpCode - , Name - , Arguments - , Doc]). - -format_arg_doc({a, N}) -> io_lib:format("Arg~w", [N]); -format_arg_doc({is,_N}) -> "Identifier"; -format_arg_doc({ii,_N}) -> "Integer"; -format_arg_doc({li,_N}) -> "[Integers]"; -format_arg_doc({t,_N}) -> "Type". From bc48b5d62ffa1e8347acd15716e19720715fd249 Mon Sep 17 00:00:00 2001 From: radrow Date: Tue, 8 Jun 2021 11:43:36 +0200 Subject: [PATCH 2/4] Styling in doc gen --- src/aeb_fate_generate_docs.erl | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/aeb_fate_generate_docs.erl b/src/aeb_fate_generate_docs.erl index e69a77c..a80e188 100644 --- a/src/aeb_fate_generate_docs.erl +++ b/src/aeb_fate_generate_docs.erl @@ -7,14 +7,13 @@ , gen_protocol_description_of_operations/1 ]). +-define(LIMA_PROTOCOL_VSN, 4). +-define(IRIS_PROTOCOL_VSN, 5). + generate_documentation(Filename, Fields) -> generate_documentation(Filename, Fields, fun(_) -> true end). generate_documentation(Filename, Fields, Filter) when is_function(Filter, 1) -> {ok, File} = file:open(Filename, [write]), - Instructions = - lists:flatten( - [gen_doc_for_op(Op, [F || F <- Fields]) - ++ "\n" || Op <- aeb_fate_generate_ops:get_ops(), Filter(Op)]), Header = lists:flatten( "|" ++ [" " ++ header_name(F) ++ " |" || F <- Fields] ++ "\n" @@ -23,6 +22,10 @@ generate_documentation(Filename, Fields, Filter) when is_function(Filter, 1) -> lists:flatten( "|" ++ [" " ++ ["-" || _ <- header_name(F)] ++ " |" || F <- Fields] ++ "\n" ), + Instructions = + lists:flatten( + [gen_doc_for_op(Op, Fields) + ++ "\n" || Op <- aeb_fate_generate_ops:get_ops(), Filter(Op)]), io:format(File, "~s~s~s\n", [Header, Separator, Instructions]), file:close(File). @@ -81,14 +84,28 @@ gen_doc_for_op(#{ opname := OpName lists:seq(0,length(FateFormat)-1))]) end; doc -> Doc; - gas -> io_lib:format("~p", [Gas]); + gas when is_integer(Gas) -> io_lib:format("~p", [Gas]); + gas when is_list(Gas) -> + lists:flatten( + string:join( + [ io_lib:format( + "~p (~s)", + [GasVal, protocol_name(Prot)] + ) + || {Prot, GasVal} <- Gas + ], ", ")); arg_types -> io_lib:format("~p", [ArgTypes]); res_type -> io_lib:format("~p", [ResType]) end - || Field <- Fields + || Field <- Fields ], " | ") ++ " |". +protocol_name(?LIMA_PROTOCOL_VSN) -> + "lima"; +protocol_name(?IRIS_PROTOCOL_VSN) -> + "iris". + format_arg_doc({a, N}) -> io_lib:format("Arg~w", [N]); format_arg_doc({is,_N}) -> "Identifier"; format_arg_doc({ii,_N}) -> "Integer"; From e860e217a0ba8fa5fd7335ebd7eb06f4452ee48a Mon Sep 17 00:00:00 2001 From: radrow Date: Tue, 8 Jun 2021 13:09:39 +0200 Subject: [PATCH 3/4] Better clone&create docs --- src/aeb_fate_generate_ops.erl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/aeb_fate_generate_ops.erl b/src/aeb_fate_generate_ops.erl index b107ecc..588d98c 100644 --- a/src/aeb_fate_generate_ops.erl +++ b/src/aeb_fate_generate_ops.erl @@ -225,10 +225,10 @@ ops_defs() -> , { 'CALL_PGR', 16#a2, true, false, true, ?GAS(100), [a,is,a,a,a,a,a], call_pgr, {contract, string, typerep, typerep, integer, integer, bool}, variant, "Potentially protected remote call. Arg5 is protected flag, otherwise as CALL_GR."} - , { 'CREATE', 16#a3, true, false, true, ?GAS(10000), [a,a,a], create, {contract_bytearray, typerep, integer}, contract, "Deploys a contract with a bytecode Arg1 and value Arg3. The `init` arguments should be placed on the stack and match the type in Arg2. Writes contract address to stack top."} - , { 'CLONE', 16#a4, true, false, true, ?GAS(5000), [a,a,a,a], clone, {contract, typerep, integer, bool}, any, "Clones the contract under Arg1 and deploys it with value of Arg3. The `init` arguments should be placed on the stack and match the type in Arg2. Writes contract (or `None` on fail when protected) to stack top."} - , { 'CLONE_G', 16#a5, true, false, true, ?GAS(5000), [a,a,a,a,a], clone_g, {contract, typerep, integer, integer, bool}, any, "Like `CLONE` but additionally limits gas of `init` call to Arg3"} - , { 'BYTECODE_HASH', 16#a6, false, true, true, ?GAS(100), [a,a], bytecode_hash, {contract}, variant, "Arg0 := hash of the deserialized contract's bytecode under address given in Arg1 (or `None` on fail)."} + , { 'CREATE', 16#a3, true, false, true, ?GAS(10000), [a,a,a], create, {contract_bytearray, typerep, integer}, contract, "Deploys a contract with a bytecode Arg1 and value Arg3. The `init` arguments should be placed on the stack and match the type in Arg2. Writes contract address to the top of the accumulator stack. If an account on the resulting address did exist before the call, the `payable` flag will be updated."} + , { 'CLONE', 16#a4, true, false, true, ?GAS(5000), [a,a,a,a], clone, {contract, typerep, integer, bool}, any, "Clones the contract under Arg1 and deploys it with value of Arg3. The `init` arguments should be placed on the stack and match the type in Arg2. Writes contract (or `None` on fail when protected) to the top of the accumulator stack. Does not copy the existing contract's store – it will be initialized by a fresh call to the `init` function. If an account on the resulting address did exist before the call, the `payable` flag will be updated."} + , { 'CLONE_G', 16#a5, true, false, true, ?GAS(5000), [a,a,a,a,a], clone_g, {contract, typerep, integer, integer, bool}, any, "Like `CLONE` but additionally limits the gas of the `init` call by Arg3"} + , { 'BYTECODE_HASH', 16#a6, false, true, true, ?GAS(100), [a,a], bytecode_hash, {contract}, variant, "Arg0 := hash of the deserialized contract's bytecode under address given in Arg1 (or `None` on fail). Fails on AEVM contracts and contracts deployed before Iris."} , { 'FEE', 16#a7, false, true, true, ?GAS(10), [a], fee, {}, integer, "Arg0 := The fee for the current call tx."} From 326fca709f6d8efbb3152d9dd035a5f68928b1de Mon Sep 17 00:00:00 2001 From: radrow Date: Tue, 8 Jun 2021 13:33:33 +0200 Subject: [PATCH 4/4] Add opcodes gen --- src/aeb_fate_generate_docs.erl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/aeb_fate_generate_docs.erl b/src/aeb_fate_generate_docs.erl index a80e188..bd2cf7c 100644 --- a/src/aeb_fate_generate_docs.erl +++ b/src/aeb_fate_generate_docs.erl @@ -5,6 +5,7 @@ -export( [ gen_protocol_opcodes_flags_and_gas/1 , gen_protocol_description_of_operations/1 + , gen_protocol_opcodes/1 ]). -define(LIMA_PROTOCOL_VSN, 4). @@ -124,3 +125,8 @@ gen_protocol_opcodes_flags_and_gas(Filename) -> generate_documentation( Filename, [opcode, opname, end_bb, in_auth, offchain, gas] ). + +gen_protocol_opcodes(Filename) -> + generate_documentation( + Filename, [opcode, opname] + ).