Skip to content
This repository has been archived by the owner on Aug 2, 2022. It is now read-only.

Commit

Permalink
abi-generator:
Browse files Browse the repository at this point in the history
- Remove namespace from the class declared in EOSIO_ABI macro.
  This prevents the generation of empty abi files when the class used in the macro is fully qualified.
- Detect `//@abi action` in class methods. This allows automatic abi generation on contracts not using the EOSIO_ABI macro.
- Remove deprecated index detection
- Add f64 (double) as a primitive type
  • Loading branch information
elmato committed Jun 9, 2018
1 parent 5bea871 commit 8de23aa
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 235 deletions.
2 changes: 1 addition & 1 deletion contracts/eosio.token/eosio.token.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* @copyright defined in eos/LICENSE.txt
*/

#include <eosio.token/eosio.token.hpp>
#include "eosio.token.hpp"

namespace eosio {

Expand Down
71 changes: 26 additions & 45 deletions libraries/abi_generator/abi_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ string abi_generator::translate_type(const string& type_name) {
else if (type_name == "long" || type_name == "int32_t") built_in_type = "int32";
else if (type_name == "short" || type_name == "int16_t") built_in_type = "int16";
else if (type_name == "char" || type_name == "int8_t") built_in_type = "int8";
else if (type_name == "double") built_in_type = "float64";
else {
static auto types = eosio::chain::common_type_defs();
auto itr = std::find_if( types.begin(), types.end(),
Expand All @@ -100,9 +101,6 @@ bool abi_generator::inspect_type_methods_for_actions(const Decl* decl) { try {
const auto* rec_decl = dyn_cast<CXXRecordDecl>(decl);
if(rec_decl == nullptr) return false;

if( rec_decl->getName().str() != target_contract )
return false;

const auto* type = rec_decl->getTypeForDecl();
ABI_ASSERT(type != nullptr);

Expand All @@ -112,9 +110,24 @@ bool abi_generator::inspect_type_methods_for_actions(const Decl* decl) { try {

auto method_name = method->getNameAsString();

// Try to get "action" annotation from method comment
bool raw_comment_is_action = false;
const RawComment* raw_comment = ast_context->getRawCommentForDeclNoCache(method);
if(raw_comment != nullptr) {
SourceManager& source_manager = ast_context->getSourceManager();
string raw_text = raw_comment->getRawText(source_manager);
regex r(R"(@abi (action)((?: [a-z0-9]+)*))");
smatch smatch;
regex_search(raw_text, smatch, r);
raw_comment_is_action = smatch.size() == 3;
}

if( std::find(target_actions.begin(), target_actions.end(), method_name) == target_actions.end() )
// Check if current method is listed the EOSIO_ABI macro
bool is_action_from_macro = rec_decl->getName().str() == target_contract && std::find(target_actions.begin(), target_actions.end(), method_name) != target_actions.end();

if(!raw_comment_is_action && !is_action_from_macro) {
return;
}

ABI_ASSERT(find_struct(method_name) == nullptr, "action already exists ${method_name}", ("method_name",method_name));

Expand Down Expand Up @@ -189,18 +202,11 @@ void abi_generator::handle_decl(const Decl* decl) { try {
return;
}

// If EOSIO_ABI macro was found, check if the current declaration
// is of the type specified in the macro and export their methods (actions).
bool type_has_actions = false;
if( target_contract.size() ) {
type_has_actions = inspect_type_methods_for_actions(decl);
}

// The current Decl was the type referenced in EOSIO_ABI macro
// Check if the current declaration has actions (EOSIO_ABI, or explicit)
bool type_has_actions = inspect_type_methods_for_actions(decl);
if( type_has_actions ) return;

// The current Decl was not the type referenced in EOSIO_ABI macro
// so we try to see if it has comments attached to the declaration
// The current Decl doesn't have actions
const RawComment* raw_comment = ast_context->getRawCommentForDeclNoCache(decl);
if(raw_comment == nullptr) {
return;
Expand Down Expand Up @@ -275,9 +281,10 @@ void abi_generator::handle_decl(const Decl* decl) { try {
table.name = params[0];
}

if(params.size() >= 2)
if(params.size() >= 2) {
table.index_type = params[1];
else { try {
ABI_ASSERT(table.index_type == "i64", "Only i64 index is supported. ${index_type}",("index_type",table.index_type));
} else { try {
guess_index_type(table, *s);
} FC_CAPTURE_AND_RETHROW( (type_name) ) }

Expand Down Expand Up @@ -324,34 +331,14 @@ void abi_generator::get_all_fields(const struct_def& s, vector<field_def>& field
}
}

bool abi_generator::is_i64i64i64_index(const vector<field_def>& fields) {
return fields.size() >= 3 && is_64bit(fields[0].type) && is_64bit(fields[1].type) && is_64bit(fields[2].type);
}

bool abi_generator::is_i64_index(const vector<field_def>& fields) {
return fields.size() >= 1 && is_64bit(fields[0].type);
}

bool abi_generator::is_i128i128_index(const vector<field_def>& fields) {
return fields.size() >= 2 && is_128bit(fields[0].type) && is_128bit(fields[1].type);
}

bool abi_generator::is_str_index(const vector<field_def>& fields) {
return fields.size() == 2 && is_string(fields[0].type);
}

void abi_generator::guess_index_type(table_def& table, const struct_def s) {

vector<field_def> fields;
get_all_fields(s, fields);

if( is_str_index(fields) ) {
table.index_type = "str";
} else if ( is_i64i64i64_index(fields) ) {
table.index_type = "i64i64i64";
} else if( is_i128i128_index(fields) ) {
table.index_type = "i128i128";
} else if( is_i64_index(fields) ) {
if( is_i64_index(fields) ) {
table.index_type = "i64";
} else {
ABI_ASSERT(false, "Unable to guess index type");
Expand All @@ -363,8 +350,7 @@ void abi_generator::guess_key_names(table_def& table, const struct_def s) {
vector<field_def> fields;
get_all_fields(s, fields);

if( table.index_type == "i64i64i64" || table.index_type == "i128i128"
|| table.index_type == "i64") {
if( table.index_type == "i64") {

table.key_names.clear();
table.key_types.clear();
Expand All @@ -376,18 +362,13 @@ void abi_generator::guess_key_names(table_def& table, const struct_def s) {
table.key_types.emplace_back(f.type);
key_size += type_size[f.type]/8;

if((table.index_type == "i64i64i64" && key_size >= sizeof(uint64_t)*3) ||
(table.index_type == "i64" && key_size >= sizeof(uint64_t)) ||
(table.index_type == "i128i128" && key_size >= sizeof(__int128)*2)) {
if(table.index_type == "i64" && key_size >= sizeof(uint64_t)) {
valid_key = true;
break;
}
}

ABI_ASSERT(valid_key, "Unable to guess key names");
} else if( table.index_type == "str" && is_str_index(fields) ) {
table.key_names = vector<field_name>{fields[0].name};
table.key_types = vector<type_name>{fields[0].type};
} else {
ABI_ASSERT(false, "Unable to guess key names");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,25 @@ namespace eosio {
callback_handler(CompilerInstance& compiler_instance, find_eosio_abi_macro_action& act)
: compiler_instance(compiler_instance), act(act) {}

string remove_namespace(const string& full_name) {
int i = full_name.size();
int on_spec = 0;
int colons = 0;
while( --i >= 0 ) {
if( full_name[i] == '>' ) {
++on_spec; colons=0;
} else if( full_name[i] == '<' ) {
--on_spec; colons=0;
} else if( full_name[i] == ':' && !on_spec) {
if (++colons == 2)
return full_name.substr(i+2);
} else {
colons = 0;
}
}
return full_name;
}

void MacroExpands (const Token &token, const MacroDefinition &md, SourceRange range, const MacroArgs *args) override {

auto* id = token.getIdentifierInfo();
Expand All @@ -366,7 +385,7 @@ namespace eosio {
auto res = regex_search(macrostr, smatch, r);
ABI_ASSERT( res );

act.contract = smatch[1].str();
act.contract = remove_namespace(smatch[1].str());

auto actions_str = smatch[2].str();
boost::trim(actions_str);
Expand Down
Loading

0 comments on commit 8de23aa

Please sign in to comment.