Skip to content

Commit da7f00a

Browse files
authored
Merge pull request #105 from aeternity/doc-gen
Ease the process of doc generation
2 parents 05dfd7f + 326fca7 commit da7f00a

2 files changed

Lines changed: 137 additions & 53 deletions

File tree

src/aeb_fate_generate_docs.erl

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
-module(aeb_fate_generate_docs).
2+
3+
-export([generate_documentation/2, generate_documentation/3]).
4+
5+
-export(
6+
[ gen_protocol_opcodes_flags_and_gas/1
7+
, gen_protocol_description_of_operations/1
8+
, gen_protocol_opcodes/1
9+
]).
10+
11+
-define(LIMA_PROTOCOL_VSN, 4).
12+
-define(IRIS_PROTOCOL_VSN, 5).
13+
14+
generate_documentation(Filename, Fields) ->
15+
generate_documentation(Filename, Fields, fun(_) -> true end).
16+
generate_documentation(Filename, Fields, Filter) when is_function(Filter, 1) ->
17+
{ok, File} = file:open(Filename, [write]),
18+
Header =
19+
lists:flatten(
20+
"|" ++ [" " ++ header_name(F) ++ " |" || F <- Fields] ++ "\n"
21+
),
22+
Separator =
23+
lists:flatten(
24+
"|" ++ [" " ++ ["-" || _ <- header_name(F)] ++ " |" || F <- Fields] ++ "\n"
25+
),
26+
Instructions =
27+
lists:flatten(
28+
[gen_doc_for_op(Op, Fields)
29+
++ "\n" || Op <- aeb_fate_generate_ops:get_ops(), Filter(Op)]),
30+
io:format(File, "~s~s~s\n", [Header, Separator, Instructions]),
31+
file:close(File).
32+
33+
header_name(opname) ->
34+
"Name";
35+
header_name(opcode) ->
36+
"Opcode";
37+
header_name(arity) ->
38+
"Arity";
39+
header_name(end_bb) ->
40+
"Ends basic block";
41+
header_name(in_auth) ->
42+
"Allowed in auth";
43+
header_name(offchain) ->
44+
"Allowed offchain";
45+
header_name(format) ->
46+
"Args";
47+
header_name(doc) ->
48+
"Description";
49+
header_name(gas) ->
50+
"Gas cost";
51+
header_name(arg_types) ->
52+
"Arg types";
53+
header_name(res_type) ->
54+
"Res type".
55+
56+
gen_doc_for_op(#{ opname := OpName
57+
, opcode := OpCode
58+
, arity := Arity
59+
, end_bb := EndBB
60+
, in_auth := InAuth
61+
, offchain := AllowedOffchain
62+
, format := FateFormat
63+
, doc := Doc
64+
, gas := Gas
65+
, arg_types := ArgTypes
66+
, res_type := ResType
67+
}, Fields) ->
68+
"| " ++
69+
string:join(
70+
[ case Field of
71+
opname -> io_lib:format("`~s`", [OpName]);
72+
opcode -> io_lib:format("0x~.16b", [OpCode]);
73+
arity -> io_lib:format("~p", [Arity]);
74+
end_bb -> io_lib:format("~p", [EndBB]);
75+
in_auth -> io_lib:format("~p", [InAuth]);
76+
offchain -> io_lib:format("~p", [AllowedOffchain]);
77+
format ->
78+
case FateFormat of
79+
[] -> "";
80+
_ -> lists:join(
81+
" ",
82+
[format_arg_doc(A) ||
83+
A <-
84+
lists:zip(FateFormat,
85+
lists:seq(0,length(FateFormat)-1))])
86+
end;
87+
doc -> Doc;
88+
gas when is_integer(Gas) -> io_lib:format("~p", [Gas]);
89+
gas when is_list(Gas) ->
90+
lists:flatten(
91+
string:join(
92+
[ io_lib:format(
93+
"~p (~s)",
94+
[GasVal, protocol_name(Prot)]
95+
)
96+
|| {Prot, GasVal} <- Gas
97+
], ", "));
98+
arg_types -> io_lib:format("~p", [ArgTypes]);
99+
res_type -> io_lib:format("~p", [ResType])
100+
end
101+
|| Field <- Fields
102+
],
103+
" | ") ++ " |".
104+
105+
protocol_name(?LIMA_PROTOCOL_VSN) ->
106+
"lima";
107+
protocol_name(?IRIS_PROTOCOL_VSN) ->
108+
"iris".
109+
110+
format_arg_doc({a, N}) -> io_lib:format("Arg~w", [N]);
111+
format_arg_doc({is,_N}) -> "Identifier";
112+
format_arg_doc({ii,_N}) -> "Integer";
113+
format_arg_doc({li,_N}) -> "[Integers]";
114+
format_arg_doc({t,_N}) -> "Type".
115+
116+
117+
%% --- protocol documentation ---
118+
119+
gen_protocol_description_of_operations(Filename) ->
120+
generate_documentation(
121+
Filename, [opname, format, doc, arg_types, res_type]
122+
).
123+
124+
gen_protocol_opcodes_flags_and_gas(Filename) ->
125+
generate_documentation(
126+
Filename, [opcode, opname, end_bb, in_auth, offchain, gas]
127+
).
128+
129+
gen_protocol_opcodes(Filename) ->
130+
generate_documentation(
131+
Filename, [opcode, opname]
132+
).

src/aeb_fate_generate_ops.erl

Lines changed: 5 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
-export([ gen_and_halt/1
44
, generate/0
5-
, generate_documentation/1
65
, get_ops/0
76
, test_asm_generator/1 ]).
87

@@ -46,7 +45,7 @@ check_numbering(_, []) -> true.
4645
-define(GAS_IRIS(A, B), [{?IRIS_PROTOCOL_VSN, B}, {?LIMA_PROTOCOL_VSN, A}]).
4746

4847
ops_defs() ->
49-
%% Opname, Opcode, end_bb, in_auth offchain, gas, format, Constructor, ArgType, ResType, Documentation
48+
%% Opname, Opcode, end_bb, in_auth,offchain, gas, format, Constructor, ArgType, ResType, Documentation
5049
[ { '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."}
5150
, { '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."}
5251
, { '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."}
@@ -226,10 +225,10 @@ ops_defs() ->
226225

227226
, { '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."}
228227

229-
, { '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."}
230-
, { '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."}
231-
, { '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"}
232-
, { '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)."}
228+
, { '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."}
229+
, { '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."}
230+
, { '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"}
231+
, { '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."}
233232

234233
, { 'FEE', 16#a7, false, true, true, ?GAS(10), [a], fee, {}, integer, "Arg0 := The fee for the current call tx."}
235234

@@ -778,50 +777,3 @@ gen_variant() ->
778777
3 -> "(| 2 | 0 | ( " ++ imm_arg() ++ ", " ++ imm_arg() ++ " ) |)"
779778
end.
780779

781-
782-
%% TODO: add gas cost and end_bb/in_auth?
783-
generate_documentation(Filename) ->
784-
{ok, File} = file:open(Filename, [write]),
785-
Instructions = lists:flatten([gen_doc(Op)++"\n" || Op <- get_ops()]),
786-
io:format(File,
787-
"### Operations\n\n"
788-
"| OpCode | Name | Args | Description |\n"
789-
"| --- | --- | --- | --- |\n"
790-
"~s"
791-
, [Instructions]),
792-
io:format(File, "\n", []),
793-
file:close(File).
794-
795-
gen_doc(#{ opname := Name
796-
, opcode := OpCode
797-
, arity := _Arity
798-
, end_bb := _EndBB
799-
, format := FateFormat
800-
, macro := _Macro
801-
, type_name := _TypeName
802-
, doc := Doc
803-
, gas := _Gas
804-
, type := _Type
805-
, constructor := _Constructor
806-
, constructor_type := _ConstructorType
807-
}) ->
808-
Arguments =
809-
case FateFormat of
810-
[] -> "";
811-
_ -> lists:join(" ",
812-
[format_arg_doc(A) ||
813-
A <-
814-
lists:zip(FateFormat,
815-
lists:seq(0,length(FateFormat)-1))])
816-
end,
817-
io_lib:format("| 0x~.16b | ~w | ~s | ~s |\n",
818-
[ OpCode
819-
, Name
820-
, Arguments
821-
, Doc]).
822-
823-
format_arg_doc({a, N}) -> io_lib:format("Arg~w", [N]);
824-
format_arg_doc({is,_N}) -> "Identifier";
825-
format_arg_doc({ii,_N}) -> "Integer";
826-
format_arg_doc({li,_N}) -> "[Integers]";
827-
format_arg_doc({t,_N}) -> "Type".

0 commit comments

Comments
 (0)