diff --git a/CHANGELOG.md b/CHANGELOG.md index 86a4c64..c6c4616 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] ### Added ### Changed +- Keyword `indexed` is now optional for word typed (`bool`, `int`, `address`, + ...) event arguments. +- State variable pretty printing now produce `'a, 'b, ...` instead of `'1, '2, ...`. +- ACI is restructured and improved: + - `state` and `event` types (if present) now appear at the top level. + - Namespaces and remote interfaces are no longer ignored. + - All type definitions are included in the interface rendering. + - API functions are renamed, new functions are `contract_interface` + and `render_aci_json`. ### Removed ## [3.0.0] - 2019-05-21 diff --git a/docs/aeso_aci.md b/docs/aeso_aci.md index 082aa6b..6a12ff3 100644 --- a/docs/aeso_aci.md +++ b/docs/aeso_aci.md @@ -30,28 +30,14 @@ generates the following JSON structure representing the contract interface: ``` json { "contract": { - "name": "Answers", - "type_defs": [ - { - "name": "state", - "vars": [], - "typedef": "{a : map(string,int)}" - }, - { - "name": "answers", - "vars": [], - "typedef": "map(string,int)" - } - ], "functions": [ { - "name": "init", "arguments": [], - "type": "{a : map(string,int)}", + "name": "init", + "returns": "Answers.state", "stateful": true }, { - "name": "new_answer", "arguments": [ { "name": "q", @@ -62,9 +48,36 @@ generates the following JSON structure representing the contract interface: "type": "int" } ], - "type": "map(string,int)", + "name": "new_answer", + "returns": { + "map": [ + "string", + "int" + ] + }, "stateful": false } + ], + "name": "Answers", + "state": { + "record": [ + { + "name": "a", + "type": "Answers.answers" + } + ] + }, + "type_defs": [ + { + "name": "answers", + "typedef": { + "map": [ + "string", + "int" + ] + }, + "vars": [] + } ] } } @@ -74,62 +87,70 @@ When that encoding is decoded the following include definition is generated: ``` contract Answers = - function new_answer : (string, int) => map(string,int) + record state = {a : Answers.answers} + type answers = map(string, int) + function init : () => Answers.state + function new_answer : (string, int) => map(string, int) ``` ### Types -``` erlang -contract_string() = string() | binary() -json_string() = binary() +```erlang +-type aci_type() :: json | string. +-type json() :: jsx:json_term(). +-type json_text() :: binary(). ``` ### Exports -#### encode(ContractString) -> {ok,JSONstring} | {error,ErrorString} +#### contract\_interface(aci\_type(), string()) -> {ok, json() | string()} | {error, term()} -Types +Generate the JSON encoding of the interface to a contract. The type definitions +and non-private functions are included in the JSON string. -``` erlang -ConstractString = contract_string() -JSONstring = json_string() -``` +#### render\_aci\_json(json() | json\_text()) -> string(). -Generate the JSON encoding of the interface to a contract. The type definitions and non-private functions are included in the JSON string. - -#### decode(JSONstring) -> ConstractString. - -Types - -``` erlang -ConstractString = contract_string() -JSONstring = json_string() -``` - -Take a JSON encoding of a contract interface and generate and generate a contract definition which can be included in another contract. +Take a JSON encoding of a contract interface and generate a contract interface +that can be included in another contract. ### Example run -This is an example of using the ACI generator from an Erlang shell. The file called `aci_test.aes` contains the contract in the description from which we want to generate files `aci_test.json` which is the JSON encoding of the contract interface and `aci_test.include` which is the contract definition to be included inside another contract. +This is an example of using the ACI generator from an Erlang shell. The file +called `aci_test.aes` contains the contract in the description from which we +want to generate files `aci_test.json` which is the JSON encoding of the +contract interface and `aci_test.include` which is the contract definition to +be included inside another contract. ``` erlang 1> {ok,Contract} = file:read_file("aci_test.aes"). {ok,<<"contract Answers =\n record state = { a : answers }\n type answers() = map(string, int)\n\n stateful function"...>>} -2> {ok,Encoding} = aeso_aci:encode(Contract). -<<"{\"contract\":{\"name\":\"Answers\",\"type_defs\":[{\"name\":\"state\",\"vars\":[],\"typedef\":\"{a : map(string,int)}\"},{\"name\":\"ans"...>> -3> file:write_file("aci_test.aci", Encoding). +2> {ok,JsonACI} = aeso_aci:contract_interface(json, Contract). +{ok,[#{contract => + #{functions => + [#{arguments => [],name => <<"init">>, + returns => <<"Answers.state">>,stateful => true}, + #{arguments => + [#{name => <<"q">>,type => <<"string">>}, + #{name => <<"a">>,type => <<"int">>}], + name => <<"new_answer">>, + returns => #{<<"map">> => [<<"string">>,<<"int">>]}, + stateful => false}], + name => <<"Answers">>, + state => + #{record => + [#{name => <<"a">>,type => <<"Answers.answers">>}]}, + type_defs => + [#{name => <<"answers">>, + typedef => #{<<"map">> => [<<"string">>,<<"int">>]}, + vars => []}]}}]} +3> file:write_file("aci_test.aci", jsx:encode(JsonACI)). ok -4> Decoded = aeso_aci:decode(Encoding). -<<"contract Answers =\n function new_answer : (string, int) => map(string,int)\n">> -5> file:write_file("aci_test.include", Decoded). +4> {ok,InterfaceStub} = aeso_aci:render_aci_json(JsonACI). +{ok,<<"contract Answers =\n record state = {a : Answers.answers}\n type answers = map(string, int)\n function init "...>>} +5> file:write_file("aci_test.include", InterfaceStub). ok -6> jsx:prettify(Encoding). -<<"{\n \"contract\": {\n \"name\": \"Answers\",\n \"type_defs\": [\n {\n \"name\": \"state\",\n \"vars\": [],\n "...>> +6> jsx:prettify(jsx:encode(JsonACI)). +<<"[\n {\n \"contract\": {\n \"functions\": [\n {\n \"arguments\": [],\n \"name\": \"init\",\n "...>> ``` -The final call to `jsx:prettify(Encoding)` returns the encoding in a -more easily readable form. This is what is shown in the description -above. - -### Notes - -The ACI generator currently cannot properly handle types defined using `datatype`. +The final call to `jsx:prettify(jsx:encode(JsonACI))` returns the encoding in a +more easily readable form. This is what is shown in the description above.