未验证 提交 a6faa2db 编写于 作者: D Daniel Larimer 提交者: GitHub

Merge pull request #1501 from EOSIO/DAWN-417-Restore-Release-ABI-Code-Generation

Dawn 417 restore release abi code generation
......@@ -39,7 +39,6 @@ pipeline {
steps {
sh '''
. $HOME/.bash_profile
export EOSLIB=$(pwd)/contracts
cd build
printf "Waiting for testing to be available..."
while /usr/bin/pgrep -x ctest > /dev/null; do sleep 1; done
......@@ -53,7 +52,6 @@ pipeline {
steps {
sh '''
. $HOME/.bash_profile
export EOSLIB=$(pwd)/contracts
cd build
printf "Waiting for testing to be available..."
while /usr/bin/pgrep -x ctest > /dev/null; do sleep 1; done
......@@ -67,7 +65,6 @@ pipeline {
steps {
sh '''
. $HOME/.bash_profile
export EOSLIB=$(pwd)/contracts
cd build
printf "Waiting for testing to be available..."
while /usr/bin/pgrep -x ctest > /dev/null; do sleep 1; done
......@@ -94,4 +91,4 @@ pipeline {
}
}
}
}
\ No newline at end of file
}
......@@ -22,11 +22,13 @@ add_subdirectory(proxy)
add_subdirectory(test_api)
add_subdirectory(test_api_mem)
add_subdirectory(test_api_db)
#add_subdirectory(simpledb)
add_subdirectory(simpledb)
#add_subdirectory(storage)
#add_subdirectory(social)
add_subdirectory(test.system)
add_subdirectory(noop)
install( DIRECTORY eosiolib DESTINATION include/ )
install( DIRECTORY musl DESTINATION include/ )
install( DIRECTORY libc++ DESTINATION include/ )
install( DIRECTORY skeleton DESTINATION share/ )
......@@ -3,73 +3,211 @@
"structs": [{
"name": "record1",
"base": "",
"fields": [
{"name":"key", "type":"uint64"},
{"name":"u256", "type":"uint256"},
{"name":"u128", "type":"uint128"},
{"name":"u64", "type":"uint64"},
{"name":"u32", "type":"uint32"},
{"name":"u16", "type":"uint16"},
{"name":"u8", "type":"uint8"},
{"name":"i64", "type":"int64"},
{"name":"i32", "type":"int32"},
{"name":"i16", "type":"int16"},
{"name":"i8", "type":"int8"},
{"name":"price", "type":"price"}
"fields": [{
"name": "key",
"type": "uint64"
},{
"name": "u256",
"type": "uint256"
},{
"name": "u128",
"type": "uint128"
},{
"name": "u64",
"type": "uint64"
},{
"name": "u32",
"type": "uint32"
},{
"name": "u16",
"type": "uint16"
},{
"name": "u8",
"type": "uint8"
},{
"name": "i64",
"type": "int64"
},{
"name": "i32",
"type": "int32"
},{
"name": "i16",
"type": "int16"
},{
"name": "i8",
"type": "int8"
}
]
},{
"name": "insert_record1",
"base": "",
"fields": [{
"name": "r1",
"type": "record1"
}
]
},{
"name": "remove_record1",
"base": "",
"fields": [{
"name": "key",
"type": "uint64"
}
]
},{
"name": "record2",
"base": "",
"fields": [
{"name":"key1", "type":"uint128"},
{"name":"key2", "type":"uint128"}
"fields": [{
"name": "key1",
"type": "uint128"
},{
"name": "key2",
"type": "uint128"
}
]
},{
"name": "insert_record2",
"base": "",
"fields": [{
"name": "r2",
"type": "record2"
}
]
},{
"name": "remove_record2",
"base": "",
"fields": [{
"name": "key",
"type": "record2"
}
]
},{
"name": "record3",
"base": "",
"fields": [
{"name":"key1", "type":"uint64"},
{"name":"key2", "type":"uint64"},
{"name":"key3", "type":"uint64"}
"fields": [{
"name": "key1",
"type": "uint64"
},{
"name": "key2",
"type": "uint64"
},{
"name": "key3",
"type": "uint64"
}
]
},{
"name": "insert_record3",
"base": "",
"fields": [{
"name": "r3",
"type": "record3"
}
]
},{
"name": "remove_record3",
"base": "",
"fields": [{
"name": "key",
"type": "record3"
}
]
},{
"name": "key_value1",
"base": "",
"fields": [
{"name":"key", "type":"string"},
{"name":"value", "type":"string"}
"fields": [{
"name": "key",
"type": "string"
},{
"name": "value",
"type": "string"
}
]
},{
"name": "insert_keyvalue1",
"base": "",
"fields": [{
"name": "kv1",
"type": "key_value1"
}
]
},{
"name": "remove_keyvalue1",
"base": "",
"fields": [{
"name": "key",
"type": "string"
}
]
},{
"name": "complex_type",
"base": "",
"fields": [
{"name":"name", "type":"string"},
{"name":"age", "type":"uint64"}
"fields": [{
"name": "name",
"type": "string"
},{
"name": "age",
"type": "uint64"
}
]
},{
"name": "key_value2",
"base": "",
"fields": [
{"name":"key", "type":"string"},
{"name":"value", "type":"complex_type"}
"fields": [{
"name": "key",
"type": "string"
},{
"name": "value",
"type": "complex_type"
}
]
},{
"name": "insert_keyvalue2",
"base": "",
"fields": [{
"name": "kv2",
"type": "key_value2"
}
]
},{
"name": "remove_keyvalue2",
"base": "",
"fields": [{
"name": "key",
"type": "string"
}
]
}
],
"actions": [{
"name": "insert1",
"type": "record1"
"type": "insert_record1"
},{
"name": "remove1",
"type": "remove_record1"
},{
"name": "insert2",
"type": "record2"
"type": "insert_record2"
},{
"name": "remove2",
"type": "remove_record2"
},{
"name": "insert3",
"type": "record3"
"type": "insert_record3"
},{
"name": "remove3",
"type": "remove_record3"
},{
"name": "insertkv1",
"type": "key_value1"
"type": "insert_keyvalue1"
},{
"name": "removekv1",
"type": "remove_keyvalue1"
},{
"name": "insertkv2",
"type": "key_value2"
"type": "insert_keyvalue2"
},{
"name": "removekv2",
"type": "remove_keyvalue2"
}
],
"tables": [{
......
......@@ -2,60 +2,225 @@
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include "simpledb.hpp"
#include "simpledb.gen.hpp"
#include <eosiolib/db.hpp>
#include <string>
#include <eosiolib/action.hpp>
#include <eosiolib/types.hpp>
#include <eosiolib/raw.hpp>
#include <eosiolib/serialize.hpp>
#include <eosiolib/db.hpp>
#include <eosiolib/system.h>
extern "C" {
using namespace eosio;
namespace simpledb {
void apply( uint64_t code, uint64_t action ) {
if( code == N(simpledb) ) {
if( action == N(insertkv1) ) {
// eosioc push message simpledb insertkv1 '{"key":"a", "value":"aa"}' -S simpledb
// eosioc get table simpledb simpledb keyvalue1
auto kv1 = eosio::current_action<key_value1>();
eosio::print("Inserting key_value1\n");
eosio::dump(kv1);
bytes b = eosio::raw::pack(kv1.value);
uint32_t err = store_str( N(simpledb), N(keyvalue1), (char *)kv1.key.get_data(), kv1.key.get_size(), (char*)b.data, b.len);
} else if( action == N(insertkv2) ) {
// eosioc push message simpledb insertkv2 '{"key":"a", "value":{"name":"aaa", "age":10}}' -S simpledb
// eosioc get table simpledb simpledb keyvalue2
auto kv2 = eosio::current_action<key_value2>();
eosio::print("Inserting key_value2\n");
eosio::dump(kv2);
bytes b = eosio::raw::pack(kv2.value);
uint32_t err = store_str( N(simpledb), N(keyvalue2), (char *)kv2.key.get_data(), kv2.key.get_size(), (char*)b.data, b.len);
} else if( action == N(insert1) ) {
// eosioc push message simpledb insert1 '{"key":75}' -S simpledb
// eosioc get table simpledb simpledb record1
auto tmp = eosio::current_action<record1>();
eosio::print("Inserting record1\n");
eosio::dump(tmp);
auto bytes = eosio::raw::pack(tmp);
store_i64( N(simpledb), N(record1), bytes.data, bytes.len);
} else if(action == N(insert2)) {
// eosioc push message simpledb insert2 '{"key1":"75", "key2":"77"}' -S simpledb
// eosioc get table simpledb simpledb record2
auto tmp = eosio::current_action<record2>();
eosio::print("Inserting record2\n");
eosio::dump(tmp);
auto bytes = eosio::raw::pack(tmp);
store_i128i128( N(simpledb), N(record2), bytes.data, bytes.len);
} else if(action == N(insert3)) {
// eosioc push message simpledb insert3 '{"key1":75, "key2":77, "key3":79}' -S simpledb
// eosioc get table simpledb simpledb record3
auto tmp = eosio::current_action<record3>();
eosio::print("Inserting record3\n");
eosio::dump(tmp);
auto bytes = eosio::raw::pack(tmp);
store_i64i64i64( N(simpledb), N(record3), bytes.data, bytes.len);
} else {
eosio_assert(0, "unknown message");
template<uint64_t Val>
struct dispatchable {
constexpr static uint64_t action_name = Val;
};
//@abi table
struct record1 {
uint64_t key;
uint256 u256;
uint128_t u128;
uint64_t u64;
uint32_t u32;
uint16_t u16;
uint8_t u8;
int64_t i64;
int32_t i32;
int16_t i16;
int8_t i8;
EOSLIB_SERIALIZE( record1, (key)(u256)(u128)(u64)(u32)(u16)(u8)(i64)(i32)(i16)(i8) );
};
//@abi action insert1
struct insert_record1 : dispatchable<N(insert1)> {
record1 r1;
void process() {
bytes b = eosio::pack(r1);
store_i64( N(simpledb), N(record1), N(simpledb), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_record1, (r1) );
};
//@abi action remove1
struct remove_record1 : dispatchable<N(remove1)> {
uint64_t key;
void process() {
remove_i64( N(simpledb), N(record1), (char *)this);
}
EOSLIB_SERIALIZE( remove_record1, (key) );
};
//@abi table
struct record2 {
uint128_t key1;
uint128_t key2;
EOSLIB_SERIALIZE( record2, (key1)(key2) );
};
//@abi action insert2
struct insert_record2 : dispatchable<N(insert2)> {
record2 r2;
void process() {
bytes b = eosio::pack(r2);
store_i128i128( N(simpledb), N(record2), N(simpledb), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_record2, (r2) );
};
//@abi action remove2
struct remove_record2 : dispatchable<N(remove2)> {
record2 key;
void process() {
bytes b = eosio::pack(key);
remove_i128i128( N(simpledb), N(record2), b.data());
}
EOSLIB_SERIALIZE( remove_record2, (key) );
};
//@abi table
struct record3 {
uint64_t key1;
uint64_t key2;
uint64_t key3;
EOSLIB_SERIALIZE( record3, (key1)(key2)(key3) );
};
//@abi action insert3
struct insert_record3 : dispatchable<N(insert3)> {
record3 r3;
void process() {
bytes b = eosio::pack(r3);
store_i128i128( N(simpledb), N(record3), N(simpledb), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_record3, (r3) );
};
//@abi action remove3
struct remove_record3 : dispatchable<N(remove3)> {
record3 key;
void process() {
bytes b = eosio::pack(key);
remove_i64i64i64( N(simpledb), N(record2), b.data());
}
EOSLIB_SERIALIZE( remove_record3, (key) );
};
//@abi table
struct key_value1 {
std::string key;
std::string value;
EOSLIB_SERIALIZE( key_value1, (key)(value) );
};
//@abi action insertkv1
struct insert_keyvalue1 : dispatchable<N(insertkv1)> {
key_value1 kv1;
void process() {
eosio_assert(false, "not implemented");
// bytes b = eosio::pack(kv1.value);
// store_str( N(simpledb), N(keyvalue1), N(simpledb), (char *)kv1.key.data(), kv1.key.size(), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_keyvalue1, (kv1) );
};
//@abi action removekv1
struct remove_keyvalue1 : dispatchable<N(removekv1)> {
std::string key;
void process() {
eosio_assert(false, "not implemented");
//remove_str( N(simpledb), N(keyvalue1), (char *)key.data(), key.size() );
}
EOSLIB_SERIALIZE( remove_keyvalue1, (key) );
};
struct complex_type {
std::string name;
uint64_t age;
EOSLIB_SERIALIZE( complex_type, (name)(age) );
};
//@abi table
struct key_value2 {
std::string key;
complex_type value;
EOSLIB_SERIALIZE( key_value2, (key)(value) );
};
//@abi action insertkv2
struct insert_keyvalue2 : dispatchable<N(insertkv2)> {
key_value2 kv2;
void process() {
eosio_assert(false, "not implemented");
// bytes b = eosio::pack(kv2.value);
// store_str( N(simpledb), N(keyvalue2), N(simpledb), (char *)kv2.key.data(), kv2.key.size(), b.data(), b.size());
}
EOSLIB_SERIALIZE( insert_keyvalue2, (kv2) );
};
//@abi action removekv2
struct remove_keyvalue2 : dispatchable<N(removekv2)> {
std::string key;
void process() {
remove_str( N(simpledb), N(keyvalue2), (char *)key.data(), key.size() );
}
EOSLIB_SERIALIZE( remove_keyvalue2, (key) );
};
template<typename ...Ts>
struct dispatcher_impl;
template<typename T>
struct dispatcher_impl<T> {
static bool dispatch(uint64_t action) {
if (action == T::action_name) {
unpack_action<T>().process();
return true;
}
return false;
}
}
};
template<typename T, typename ...Rem>
struct dispatcher_impl<T, Rem...> {
static bool dispatch(uint64_t action) {
return dispatcher_impl<T>::dispatch(action) || dispatcher_impl<Rem...>::dispatch(action);
}
};
using dispatcher = dispatcher_impl<insert_record1, remove_record1, insert_record2, insert_record3, insert_keyvalue1, insert_keyvalue2>;
}
extern "C" {
/// The apply method implements the dispatch of events to this contract
void apply( uint64_t code, uint64_t act ) {
if (code == current_receiver()) {
auto action_processed = simpledb::dispatcher::dispatch(act);
eosio_assert(action_processed, "unknown action");
}
}
}
\ No newline at end of file
#pragma once
#include <eosiolib/types.hpp>
#include <eosiolib/datastream.hpp>
#include <eosiolib/raw_fwd.hpp>
namespace eosio { namespace raw {
template<typename Stream> inline void pack( Stream& s, const record1& value ) {
raw::pack(s, value.key);
raw::pack(s, value.u256);
raw::pack(s, value.u128);
raw::pack(s, value.u64);
raw::pack(s, value.u32);
raw::pack(s, value.u16);
raw::pack(s, value.u8);
raw::pack(s, value.i64);
raw::pack(s, value.i32);
raw::pack(s, value.i16);
raw::pack(s, value.i8);
raw::pack(s, value.price);
}
template<typename Stream> inline void unpack( Stream& s, record1& value ) {
raw::unpack(s, value.key);
raw::unpack(s, value.u256);
raw::unpack(s, value.u128);
raw::unpack(s, value.u64);
raw::unpack(s, value.u32);
raw::unpack(s, value.u16);
raw::unpack(s, value.u8);
raw::unpack(s, value.i64);
raw::unpack(s, value.i32);
raw::unpack(s, value.i16);
raw::unpack(s, value.i8);
raw::unpack(s, value.price);
}
template<typename Stream> inline void pack( Stream& s, const record2& value ) {
raw::pack(s, value.key1);
raw::pack(s, value.key2);
}
template<typename Stream> inline void unpack( Stream& s, record2& value ) {
raw::unpack(s, value.key1);
raw::unpack(s, value.key2);
}
template<typename Stream> inline void pack( Stream& s, const record3& value ) {
raw::pack(s, value.key1);
raw::pack(s, value.key2);
raw::pack(s, value.key3);
}
template<typename Stream> inline void unpack( Stream& s, record3& value ) {
raw::unpack(s, value.key1);
raw::unpack(s, value.key2);
raw::unpack(s, value.key3);
}
template<typename Stream> inline void pack( Stream& s, const key_value1& value ) {
raw::pack(s, value.key);
raw::pack(s, value.value);
}
template<typename Stream> inline void unpack( Stream& s, key_value1& value ) {
raw::unpack(s, value.key);
raw::unpack(s, value.value);
}
template<typename Stream> inline void pack( Stream& s, const complex_type& value ) {
raw::pack(s, value.name);
raw::pack(s, value.age);
}
template<typename Stream> inline void unpack( Stream& s, complex_type& value ) {
raw::unpack(s, value.name);
raw::unpack(s, value.age);
}
template<typename Stream> inline void pack( Stream& s, const key_value2& value ) {
raw::pack(s, value.key);
raw::pack(s, value.value);
}
template<typename Stream> inline void unpack( Stream& s, key_value2& value ) {
raw::unpack(s, value.key);
raw::unpack(s, value.value);
}
} }
#include <eosiolib/raw.hpp>
namespace eosio {
void print_ident(int n){while(n-->0){print(" ");}};
template<typename Type>
Type current_message_ex() {
uint32_t size = action_size();
char* data = (char *)eosio::malloc(size);
eos_assert(data && read_action(data, size) == size, "error reading message");
Type value;
eosio::raw::unpack(data, size, value);
eosio::free(data);
return value;
}
void dump(const record1& value, int tab=0) {
print_ident(tab);print("key:[");printi(uint64_t(value.key));print("]\n");
print_ident(tab);print("u256:[");printhex((void*)&value.u256, sizeof(value.u256));print("]\n");
print_ident(tab);print("u128:[");printi128(&value.u128);print("]\n");
print_ident(tab);print("u64:[");printi(uint64_t(value.u64));print("]\n");
print_ident(tab);print("u32:[");printi(uint64_t(value.u32));print("]\n");
print_ident(tab);print("u16:[");printi(uint64_t(value.u16));print("]\n");
print_ident(tab);print("u8:[");printi(uint64_t(value.u8));print("]\n");
print_ident(tab);print("i64:[");printi(uint64_t(value.i64));print("]\n");
print_ident(tab);print("i32:[");printi(uint64_t(value.i32));print("]\n");
print_ident(tab);print("i16:[");printi(uint64_t(value.i16));print("]\n");
print_ident(tab);print("i8:[");printi(uint64_t(value.i8));print("]\n");
print_ident(tab);print("price:[");print("]\n");
}
template<>
record1 current_action<record1>() {
return current_message_ex<record1>();
}
void dump(const record2& value, int tab=0) {
print_ident(tab);print("key1:[");printi128(&value.key1);print("]\n");
print_ident(tab);print("key2:[");printi128(&value.key2);print("]\n");
}
template<>
record2 current_action<record2>() {
return current_message_ex<record2>();
}
void dump(const record3& value, int tab=0) {
print_ident(tab);print("key1:[");printi(uint64_t(value.key1));print("]\n");
print_ident(tab);print("key2:[");printi(uint64_t(value.key2));print("]\n");
print_ident(tab);print("key3:[");printi(uint64_t(value.key3));print("]\n");
}
template<>
record3 current_action<record3>() {
return current_message_ex<record3>();
}
void dump(const key_value1& value, int tab=0) {
print_ident(tab);print("key:[");print("]\n");
print_ident(tab);print("value:[");print("]\n");
}
template<>
key_value1 current_action<key_value1>() {
return current_message_ex<key_value1>();
}
void dump(const complex_type& value, int tab=0) {
print_ident(tab);print("name:[");print("]\n");
print_ident(tab);print("age:[");printi(uint64_t(value.age));print("]\n");
}
template<>
complex_type current_action<complex_type>() {
return current_message_ex<complex_type>();
}
void dump(const key_value2& value, int tab=0) {
print_ident(tab);print("key:[");print("]\n");
print_ident(tab);print("value:[");print("\n"); eosio::dump(value.value, tab+1);print_ident(tab);print("]\n");
}
template<>
key_value2 current_action<key_value2>() {
return current_message_ex<key_value2>();
}
} //eosio
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
#include <eosiolib/eos.hpp>
#include <eosiolib/string.hpp>
/* @abi action insert1
* @abi table
*/
struct record1 {
uint64_t key;
uint256 u256;
uint128_t u128;
uint64_t u64;
uint32_t u32;
uint16_t u16;
uint8_t u8;
int64_t i64;
int32_t i32;
int16_t i16;
int8_t i8;
price price;
};
/* @abi action insert2
* @abi table
*/
struct record2 {
uint128_t key1;
uint128_t key2;
};
/* @abi action insert3
* @abi table
*/
struct record3 {
uint64_t key1;
uint64_t key2;
uint64_t key3;
};
/* @abi action insertkv1
* @abi table
*/
struct key_value1 {
eosio::string key;
eosio::string value;
};
struct complex_type {
eosio::string name;
uint64_t age;
};
/* @abi action insertkv2
* @abi table
*/
struct key_value2 {
eosio::string key;
complex_type value;
};
......@@ -27,18 +27,29 @@ void abi_generator::set_compiler_instance(CompilerInstance& compiler_instance) {
}
void abi_generator::handle_tagdecl_definition(TagDecl* tag_decl) {
ASTContext& ctx = tag_decl->getASTContext();
auto decl_location = tag_decl->getLocation().printToString(ctx.getSourceManager());
ast_context = &tag_decl->getASTContext();
auto decl_location = tag_decl->getLocation().printToString(ast_context->getSourceManager());
try {
handle_decl(tag_decl);
} FC_CAPTURE_AND_RETHROW((decl_location)) }
string abi_generator::remove_namespace(const string& full_name) {
string type_name = full_name;
auto pos = type_name.find_last_of("::");
if(pos != string::npos)
type_name = type_name.substr(pos+1);
return type_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;
}
bool abi_generator::is_builtin_type(const string& type_name) {
......@@ -70,13 +81,14 @@ void abi_generator::handle_decl(const Decl* decl) { try {
ABI_ASSERT(decl != nullptr);
ABI_ASSERT(output != nullptr);
ABI_ASSERT(ast_context != nullptr);
ASTContext& ctx = decl->getASTContext();
const RawComment* raw_comment = ctx.getRawCommentForDeclNoCache(decl);
//ASTContext& ctx = decl->getASTContext();
const RawComment* raw_comment = ast_context->getRawCommentForDeclNoCache(decl);
if(!raw_comment) return;
SourceManager& source_manager = ctx.getSourceManager();
SourceManager& source_manager = ast_context->getSourceManager();
auto file_name = source_manager.getFilename(raw_comment->getLocStart());
if ( !abi_context.empty() && !file_name.startswith(abi_context) ) {
return;
......@@ -105,7 +117,7 @@ void abi_generator::handle_decl(const Decl* decl) { try {
auto qt = action_decl->getTypeForDecl()->getCanonicalTypeInternal();
auto type_name = remove_namespace(add_struct(qt));
auto type_name = add_struct(qt);
ABI_ASSERT(!is_builtin_type(type_name),
"A built-in type with the same name exists, try using another name: ${type_name}", ("type_name",type_name));
......@@ -128,7 +140,7 @@ void abi_generator::handle_decl(const Decl* decl) { try {
ABI_ASSERT(table_decl != nullptr);
auto qt = table_decl->getTypeForDecl()->getCanonicalTypeInternal();
auto type_name = remove_namespace(add_struct(qt));
auto type_name = add_struct(qt);
ABI_ASSERT(!is_builtin_type(type_name),
"A built-in type with the same name exists, try using another name: ${type_name}", ("type_name",type_name));
......@@ -140,16 +152,16 @@ void abi_generator::handle_decl(const Decl* decl) { try {
table.name = boost::algorithm::to_lower_copy(boost::erase_all_copy(type_name, "_"));
table.type = type_name;
if(params.size() >= 1)
table.index_type = params[0];
if(params.size() >= 1) {
table.name = params[0];
}
if(params.size() >= 2)
table.index_type = params[1];
else { try {
guess_index_type(table, *s);
} FC_CAPTURE_AND_RETHROW( (type_name) ) }
if(params.size() >= 2) {
table.name = params[1];
}
try {
guess_key_names(table, *s);
} FC_CAPTURE_AND_RETHROW( (type_name) )
......@@ -181,9 +193,11 @@ bool abi_generator::is_string(const string& type) {
void abi_generator::get_all_fields(const struct_def& s, vector<field_def>& fields) {
abi_serializer abis(*output);
for(const auto& field : s.fields) {
fields.push_back(field);
}
if(s.base.size()) {
const auto* base = find_struct(s.base);
ABI_ASSERT(base, "Unable to find base type ${type}",("type",s.base));
......@@ -211,7 +225,7 @@ 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) ) {
......@@ -230,15 +244,28 @@ 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" && is_i64i64i64_index(fields) ) {
table.key_names = vector<field_name>{fields[0].name, fields[1].name, fields[2].name};
table.key_types = vector<type_name>{fields[0].type, fields[1].type, fields[2].type};
} else if( table.index_type == "i128i128" && is_i128i128_index(fields) ) {
table.key_names = vector<field_name>{fields[0].name, fields[1].name};
table.key_types = vector<type_name>{fields[0].type, fields[1].type};
} else if( table.index_type == "i64" && is_i64_index(fields) ) {
table.key_names = vector<field_name>{fields[0].name};
table.key_types = vector<type_name>{fields[0].type};
if( table.index_type == "i64i64i64" || table.index_type == "i128i128"
|| table.index_type == "i64") {
table.key_names.clear();
table.key_types.clear();
unsigned int key_size = 0;
bool valid_key = false;
for(auto& f : fields) {
table.key_names.emplace_back(f.name);
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)) {
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};
......@@ -298,95 +325,196 @@ bool abi_generator::is_one_filed_no_base(const string& type_name) {
}
string abi_generator::decl_to_string(clang::Decl* d) {
ASTContext& ctx = d->getASTContext();
const auto& sm = ctx.getSourceManager();
//ASTContext& ctx = d->getASTContext();
const auto& sm = ast_context->getSourceManager();
clang::SourceLocation b(d->getLocStart()), _e(d->getLocEnd());
clang::SourceLocation e(clang::Lexer::getLocForEndOfToken(_e, 0, sm, compiler_instance->getLangOpts()));
return string(sm.getCharacterData(b),
sm.getCharacterData(e)-sm.getCharacterData(b));
}
void abi_generator::add_typedef(const clang::TypedefType* typeDef) {
bool abi_generator::is_typedef(const clang::QualType& qt) {
return isa<TypedefType>(qt.getTypePtr());
}
vector<type_def> types_to_add;
while(typeDef != nullptr) {
const auto* typedef_decl = typeDef->getDecl();
auto qt = typedef_decl->getUnderlyingType().getUnqualifiedType();
bool abi_generator::is_elaborated(const clang::QualType& qt) {
return isa<ElaboratedType>(qt.getTypePtr());
}
auto full_name = translate_type(qt.getAsString(compiler_instance->getLangOpts()));
bool abi_generator::is_vector(const clang::QualType& vqt) {
QualType qt(vqt);
//HACK: We need to think another way to stop importing the "typedef chain"
if( full_name.find("<") != string::npos ) {
break;
}
if ( is_elaborated(qt) )
qt = qt->getAs<clang::ElaboratedType>()->getNamedType();
auto new_type_name = translate_type(typedef_decl->getName().str());
if(is_builtin_type(new_type_name)) {
break;
}
return isa<clang::TemplateSpecializationType>(qt.getTypePtr()) \
&& boost::starts_with( get_type_name(qt, false), "vector");
}
bool abi_generator::is_vector(const string& type_name) {
return boost::ends_with(type_name, "[]");
}
//TODO: ABI_ASSERT TypeName length for typedef
type_def abi_typedef;
abi_typedef.new_type_name = new_type_name;
abi_typedef.type = remove_namespace( full_name );
bool abi_generator::is_struct_specialization(const clang::QualType& qt) {
return is_struct(qt) && isa<clang::TemplateSpecializationType>(qt.getTypePtr());
}
const auto* td = find_type(abi_typedef.new_type_name);
if( td ) {
ABI_ASSERT(abi_typedef.type == td->type);
typeDef = qt->getAs<clang::TypedefType>();
continue;
}
bool abi_generator::is_struct(const clang::QualType& sqt) {
clang::QualType qt(sqt);
const auto* type = qt.getTypePtr();
return !is_vector(qt) && (type->isStructureType() || type->isClassType());
}
clang::QualType abi_generator::get_vector_element_type(const clang::QualType& qt) {
const auto* tst = clang::dyn_cast<const clang::TemplateSpecializationType>(qt.getTypePtr());
ABI_ASSERT(tst != nullptr);
const clang::TemplateArgument& arg0 = tst->getArg(0);
return arg0.getAsType();
}
string abi_generator::get_vector_element_type(const string& type_name) {
if( is_vector(type_name) )
return type_name.substr(0, type_name.size()-2);
return type_name;
}
string abi_generator::get_type_name(const clang::QualType& qt, bool with_namespace=false) {
auto name = clang::TypeName::getFullyQualifiedName(qt, *ast_context);
if(!with_namespace)
name = remove_namespace(name);
return name;
}
clang::QualType abi_generator::add_typedef(const clang::QualType& tqt) {
//ilog("addTypeDef => ${a} ${b} [${c}]", ("a",abi_typedef.new_type_name)("b",abi_typedef.type)("c",getFullScope(qt)));
ABI_ASSERT(abi_typedef.new_type_name != abi_typedef.type,
"Unable to export typedef `${td}` at ${at}",
("td",decl_to_string(typeDef->getDecl()))
("at",typeDef->getDecl()->getLocation().printToString(typeDef->getDecl()->getASTContext().getSourceManager()))
);
clang::QualType qt(get_named_type_if_elaborated(tqt));
types_to_add.push_back(abi_typedef);
typeDef = qt->getAs<clang::TypedefType>();
const auto* td_decl = qt->getAs<clang::TypedefType>()->getDecl();
auto underlying_type = td_decl->getUnderlyingType().getUnqualifiedType();
auto new_type_name = td_decl->getName().str();
auto underlying_type_name = get_type_name(underlying_type);
if ( is_vector(underlying_type) ) {
underlying_type_name = add_vector(underlying_type);
}
type_def abi_typedef;
abi_typedef.new_type_name = new_type_name;
abi_typedef.type = translate_type(underlying_type_name);
const auto* td = find_type(abi_typedef.new_type_name);
if(!td && !is_struct_specialization(underlying_type) ) {
output->types.push_back(abi_typedef);
} else {
if(td) ABI_ASSERT(abi_typedef.type == td->type);
}
std::reverse(types_to_add.begin(), types_to_add.end());
output->types.insert(output->types.end(), types_to_add.begin(), types_to_add.end());
if( is_typedef(underlying_type) && !is_builtin_type(get_type_name(underlying_type)) )
return add_typedef(underlying_type);
return underlying_type;
}
string abi_generator::get_name_to_add(const clang::QualType& qual_type) {
clang::CXXRecordDecl::base_class_range abi_generator::get_struct_bases(const clang::QualType& sqt) {
auto type_name = qual_type.getAsString(compiler_instance->getLangOpts());
const auto* typedef_type = qual_type->getAs<clang::TypedefType>();
if( !is_builtin_type(type_name) && typedef_type != nullptr) {
add_typedef(typedef_type);
}
clang::QualType qt(sqt);
if(is_typedef(qt)) {
const auto* td_decl = qt->getAs<clang::TypedefType>()->getDecl();
qt = td_decl->getUnderlyingType().getUnqualifiedType();
}
const auto* record_type = qt->getAs<clang::RecordType>();
ABI_ASSERT(record_type != nullptr);
auto cxxrecord_decl = clang::dyn_cast<CXXRecordDecl>(record_type->getDecl());
ABI_ASSERT(cxxrecord_decl != nullptr);
//record_type->getCanonicalTypeInternal().dump();
return type_name;
auto bases = cxxrecord_decl->bases();
return bases;
}
string abi_generator::add_struct(const clang::QualType& qual_type) {
const clang::RecordDecl::field_range abi_generator::get_struct_fields(const clang::QualType& sqt) {
clang::QualType qt(sqt);
ABI_ASSERT(output != nullptr);
if(is_typedef(qt)) {
const auto* td_decl = qt->getAs<clang::TypedefType>()->getDecl();
qt = td_decl->getUnderlyingType().getUnqualifiedType();
}
const auto* record_type = qual_type->getAs<clang::RecordType>();
const auto* record_type = qt->getAs<clang::RecordType>();
ABI_ASSERT(record_type != nullptr);
return record_type->getDecl()->fields();
}
string abi_generator::add_vector(const clang::QualType& vqt) {
clang::QualType qt(get_named_type_if_elaborated(vqt));
auto vector_element_type = get_vector_element_type(qt);
ABI_ASSERT(!is_vector(vector_element_type), "Only one-dimensional arrays are supported");
const auto* record_decl = clang::cast_or_null<clang::CXXRecordDecl>(record_type->getDecl()->getDefinition());
ABI_ASSERT(record_decl != nullptr);
add_type(vector_element_type);
auto vector_element_type_str = translate_type(get_type_name(vector_element_type));
vector_element_type_str += "[]";
ASTContext& ctx = record_decl->getASTContext();
return vector_element_type_str;
}
auto full_name = get_name_to_add(qual_type);
string abi_generator::add_type(const clang::QualType& tqt) {
auto name = remove_namespace(full_name);
clang::QualType qt(get_named_type_if_elaborated(tqt));
//Only export user defined types
if( is_builtin_type(name) ) {
return name;
string full_type_name = translate_type(get_type_name(qt, true));
string type_name = translate_type(get_type_name(qt));
bool is_type_def = false;
if( is_builtin_type(type_name) ) {
return type_name;
}
if( is_typedef(qt) ) {
qt = add_typedef(qt);
if( is_builtin_type(translate_type(get_type_name(qt))) ) {
return type_name;
}
is_type_def = true;
}
if( is_vector(qt) ) {
auto vector_type_name = add_vector(qt);
return is_type_def ? type_name : vector_type_name;
}
if( is_struct(qt) ) {
return add_struct(qt, full_type_name);
}
ABI_ASSERT(false, "types can only be: vector, struct, class or a built-in type. (${type}) ", ("type",get_type_name(qt)));
return type_name;
}
clang::QualType abi_generator::get_named_type_if_elaborated(const clang::QualType& qt) {
if( is_elaborated(qt) ) {
return qt->getAs<clang::ElaboratedType>()->getNamedType();
}
return qt;
}
const auto* type = qual_type.getTypePtr();
string abi_generator::add_struct(const clang::QualType& sqt, string full_name) {
clang::QualType qt(get_named_type_if_elaborated(sqt));
if( full_name.empty() ) {
full_name = get_type_name(qt, true);
}
ABI_ASSERT(type->isStructureType() || type->isClassType(), "Only struct and class are supported. ${full_name}",("full_name",full_name));
auto name = remove_namespace(full_name);
ABI_ASSERT(is_struct(qt), "Only struct and class are supported. ${full_name}",("full_name",full_name));
ABI_ASSERT(name.size() <= sizeof(type_name),
"Type name > ${maxsize}, ${name}",
......@@ -400,58 +528,52 @@ string abi_generator::add_struct(const clang::QualType& qual_type) {
return name;
}
auto bases = record_decl->bases();
auto total_bases = distance(bases.begin(), bases.end());
if( total_bases > 1 ) {
ABI_ASSERT(false, "Multiple inheritance not supported - ${type}", ("type",full_name));
}
auto bases = get_struct_bases(qt);
auto bitr = bases.begin();
int total_bases = 0;
string base_name;
if( total_bases == 1 ) {
auto qt = bases.begin()->getType();
base_name = add_struct(qt);
while( bitr != bases.end() ) {
auto base_qt = bitr->getType();
const auto* record_type = base_qt->getAs<clang::RecordType>();
if( record_type && is_struct(base_qt) && !record_type->getDecl()->field_empty() ) {
ABI_ASSERT(total_bases == 0, "Multiple inheritance not supported - ${type}", ("type",full_name));
base_name = add_type(base_qt);
++total_bases;
}
++bitr;
}
struct_def abi_struct;
for (const auto& field : record_decl->fields()) {
field_def struct_field;
for (const clang::FieldDecl* field : get_struct_fields(qt) ) {
clang::QualType qt = field->getType();
string field_name = field->getNameAsString();
string field_type_name = add_type(qt);
auto field_type = translate_type(remove_namespace(get_name_to_add(qt.getUnqualifiedType())));
ABI_ASSERT(field_type.size() <= sizeof(decltype(struct_field.type)),
"Type name > ${maxsize}, ${type}::${name}", ("type",full_name)("name",field_type)("maxsize",sizeof(decltype(struct_field.type))));
field_def struct_field{field_name, field_type_name};
ABI_ASSERT(is_builtin_type(get_vector_element_type(struct_field.type))
|| find_struct(get_vector_element_type(struct_field.type))
|| find_type(get_vector_element_type(struct_field.type))
, "Unknown type ${type} [${abi}]",("type",struct_field.type)("abi",*output));
ABI_ASSERT(field->getNameAsString().size() <= sizeof(decltype(struct_field.name)) ,
"Field name > ${maxsize}, ${type}::${name}", ("type",full_name)("name",field->getNameAsString())("maxsize", sizeof(decltype(struct_field.name))));
if( qt->getAs<clang::RecordType>() ) {
add_struct(qt);
//TODO: simplify if OPT_SINGLE_FIELD_STRUCT is enabled
}
struct_field.name = field->getNameAsString();
struct_field.type = field_type;
ABI_ASSERT(struct_field.type.size() <= sizeof(decltype(struct_field.type)),
"Type name > ${maxsize}, ${type}::${name}", ("type",struct_field.type)("name",struct_field.name)("maxsize",sizeof(decltype(struct_field.type))));
ABI_ASSERT(is_builtin_type(struct_field.type) || find_struct(struct_field.type), "Unknown type ${type} ${name} ${ttt} ${sss}", ("type",struct_field.type)("name",struct_field.name)("types", output->types)("structs",output->structs));
ABI_ASSERT(field->getNameAsString().size() <= sizeof(decltype(struct_field.name)) ,
"Field name > ${maxsize}, ${type}::${name}", ("type",struct_field.type)("name",struct_field.name)("maxsize",sizeof(decltype(struct_field.type))));
type_size[string(struct_field.type)] = ctx.getTypeSize(qt);
type_size[string(struct_field.type)] = is_vector(struct_field.type) ? 0 : ast_context->getTypeSize(qt);
abi_struct.fields.push_back(struct_field);
}
abi_struct.name = resolve_type(name);
abi_struct.base = remove_namespace(base_name);
output->structs.push_back(abi_struct);
if(verbose) {
cerr << "Adding type " << resolve_type(name) << " (" << full_name << ")\n";
}
abi_struct.base = base_name;
output->structs.push_back(abi_struct);
full_types[name] = full_name;
return full_name;
return name;
}
}
\ No newline at end of file
......@@ -19,6 +19,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Core/QualTypeNames.h"
#include "llvm/Support/raw_ostream.h"
#include <boost/algorithm/string.hpp>
......@@ -60,7 +61,7 @@ namespace eosio {
map<string, uint64_t> type_size;
map<string, string> full_types;
string abi_context;
clang::ASTContext* ast_context;
public:
enum optimization {
......@@ -70,7 +71,8 @@ namespace eosio {
abi_generator()
:optimizations(0)
, output(nullptr)
, compiler_instance(nullptr)
, compiler_instance(nullptr)
, ast_context(nullptr)
{}
~abi_generator() {}
......@@ -161,11 +163,29 @@ namespace eosio {
string decl_to_string(clang::Decl* d);
void add_typedef(const clang::TypedefType* typeDef);
bool is_typedef(const clang::QualType& qt);
QualType add_typedef(const clang::QualType& qt);
bool is_vector(const clang::QualType& qt);
bool is_vector(const string& type_name);
string add_vector(const clang::QualType& qt);
bool is_struct(const clang::QualType& qt);
string add_struct(const clang::QualType& qt, string full_type_name="");
string get_type_name(const clang::QualType& qt, bool no_namespace);
string add_type(const clang::QualType& tqt);
bool is_elaborated(const clang::QualType& qt);
bool is_struct_specialization(const clang::QualType& qt);
string get_name_to_add(const clang::QualType& qual_type);
QualType get_vector_element_type(const clang::QualType& qt);
string get_vector_element_type(const string& type_name);
clang::QualType get_named_type_if_elaborated(const clang::QualType& qt);
string add_struct(const clang::QualType& qual_type);
const clang::RecordDecl::field_range get_struct_fields(const clang::QualType& qt);
clang::CXXRecordDecl::base_class_range get_struct_bases(const clang::QualType& qt);
};
struct abi_generator_astconsumer : public ASTConsumer {
......
......@@ -2,6 +2,5 @@ add_subdirectory( eosiod )
add_subdirectory( eosioc )
add_subdirectory( eosiowd )
add_subdirectory( eosio-launcher )
add_subdirectory( eosio-codegen )
add_subdirectory( eosio-applesedemo )
add_subdirectory( eosio-abigen )
......@@ -42,16 +42,14 @@ static cl::opt<bool> abi_opt_sfs(
cl::desc("Optimize single field struct"),
cl::cat(abi_generator_category));
int main(int argc, const char **argv) { try {
int main(int argc, const char **argv) { abi_def output; try {
CommonOptionsParser op(argc, argv, abi_generator_category);
ClangTool Tool(op.getCompilations(), op.getSourcePathList());
abi_def abi;
int result = Tool.run(create_factory(abi_verbose, abi_opt_sfs, abi_context, abi).get());
int result = Tool.run(create_factory(abi_verbose, abi_opt_sfs, abi_context, output).get());
if(!result) {
abi_serializer(abi).validate();
fc::json::save_to_file<abi_def>(abi, abi_destination, true);
abi_serializer(output).validate();
fc::json::save_to_file<abi_def>(output, abi_destination, true);
}
return result;
} FC_CAPTURE_AND_LOG(()); return -1; }
} FC_CAPTURE_AND_LOG((output)); return -1; }
add_executable( eosio-codegen main.cpp )
if( UNIX AND NOT APPLE )
set(rt_library rt )
endif()
find_package( Gperftools QUIET )
if( GPERFTOOLS_FOUND )
message( STATUS "Found gperftools; compiling steemd with TCMalloc")
list( APPEND PLATFORM_SPECIFIC_LIBS tcmalloc )
endif()
target_link_libraries( eosio-codegen
PRIVATE fc eosio_chain ${CMAKE_DL_LIBS} ${PLATFORM_SPECIFIC_LIBS} )
install( TARGETS
eosio-codegen
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
/**
* @file
* @copyright defined in eos/LICENSE.txt
* @brief generates serialization/deserialization functions for contracts types
**/
#include <string>
#include <sstream>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <eosio/chain/types.hpp>
#include <eosio/chain/contracts/abi_serializer.hpp>
#include <fc/io/json.hpp>
using namespace std;
using namespace eosio::chain::contracts;
const string tab = " ";
struct codegen {
abi_def abi;
abi_serializer abis;
codegen(const abi_def& abi)
:abi(abi)
{
abis.set_abi(abi);
}
void generate_ident(ostringstream& output) {
output << tab << "void print_ident(int n){while(n-->0){print(\" \");}};" << endl;
}
void generate_dump(ostringstream& output, const struct_def& type) {
output << tab << "void dump(const " << type.name << "& value, int tab=0) {" << endl;
for(const auto& field : type.fields ) {
auto field_type = abis.resolve_type(field.type);
output << tab << tab << "print_ident(tab);";
output << "print(\"" << field.name << ":[\");";
if( abis.is_struct(field_type) ) {
output << "print(\"\\n\"); eosio::dump(value."<< field.name <<", tab+1);";
output << "print_ident(tab);";
} else if( field_type == "string" ) {
output << "prints_l(value."<< field.name <<".get_data(), value."<< field.name <<".get_size());";
} else if( field_type == "fixed_string32" || field_type == "fixed_string16" ) {
output << "prints_l(value."<< field.name <<".str, value."<< field.name <<".len);";
} else if( field_type == "Bytes" ) {
output << "printhex(value."<< field.name <<".data, value."<< field.name <<".len);";
} else if( abis.is_integer(field_type) ) {
auto size = abis.get_integer_size(field_type);
if(size <= 64) {
output << "printi(uint64_t(value."<< field.name <<"));";
} else if (size == 128) {
output << "printi128(&value."<< field.name <<");";
} else if (size == 256) {
output << "printhex((void*)&value."<< field.name <<", sizeof(value."<< field.name <<"));";
}
} else if( field_type == "bytes" ) {
output << "printhex(value."<< field.name <<".data, value."<< field.name <<".len);";
} else if( field_type == "name" || field_type == "account_name" || field_type == "permission_name" ||\
field_type == "token_name" || field_type == "table_name" || field_type == "func_name" ) {
output << "printn(value."<< field.name <<");";
} else if( field_type == "public_key" ) {
output << "printhex((void*)value."<< field.name <<".data, 33);";
} else if( field_type == "time" ) {
output << "printi(value."<< field.name <<");";
} else if( field_type == "price" ) {
output << "printi(value."<< field.name <<".base.amount);print(\"/\");printi(value."<< field.name <<".quote.amount);";
} else {
}
output << "print(\"]\\n\");" << endl;
}
output << tab << "}" << endl;
}
void generate_current_message_ex(ostringstream& output) {
output << tab << "template<typename Type>" << endl;
output << tab << "Type current_message_ex() {" << endl;
output << tab << tab << "uint32_t size = message_size();" << endl;
output << tab << tab << "char* data = (char *)eosio::malloc(size);" << endl;
output << tab << tab << "assert(data && read_message(data, size) == size, \"error reading message\");" << endl;
output << tab << tab << "Type value;" << endl;
output << tab << tab << "eosio::raw::unpack(data, size, value);" << endl;
output << tab << tab << "eosio::free(data);" << endl;
output << tab << tab << "return value;" << endl;
output << tab << "}" << endl;
}
void generate_current_message(ostringstream& output, const struct_def& type) {
output << tab << "template<>" << endl;
output << tab << type.name << " current_message<" << type.name << ">() {" << endl;
output << tab << tab << "return current_message_ex<" << type.name << ">();" << endl;
output << tab << "}" << endl;
}
void generate_pack(ostringstream& output, const struct_def& type) {
output << tab << "template<typename Stream> inline void pack( Stream& s, const " << type.name << "& value ) {" << endl;
for(const auto& field : type.fields ) {
output << tab << tab << "raw::pack(s, value." << field.name << ");" << endl;
}
if( type.base != type_name() )
output << tab << tab << "raw::pack(s, static_cast<const " << type.base << "&>(value));" << endl;
output << tab << "}" << endl;
}
void generate_unpack(ostringstream& output, const struct_def& type) {
output << tab << "template<typename Stream> inline void unpack( Stream& s, " << type.name << "& value ) {" << endl;
for(const auto& field : type.fields ) {
output << tab << tab << "raw::unpack(s, value." << field.name << ");" << endl;
}
if( type.base != type_name() )
output << tab << tab << "raw::unpack(s, static_cast<" << type.base << "&>(value));" << endl;
output << tab << "}" << endl;
}
void generate() {
ostringstream output;
output << "#pragma once" << endl;
output << "#include <eosiolib/types.hpp>" << endl;
output << "#include <eosiolib/message.hpp>" << endl;
output << "#include <eosiolib/datastream.hpp>" << endl;
output << "#include <eosiolib/raw_fwd.hpp>" << endl;
output << endl;
//Generate serialization/deserialization for every cotract type
output << "namespace eosio { namespace raw {" << endl;
for(const auto& type : abi.structs) {
generate_pack(output, type);
generate_unpack(output, type);
}
output << "} }" << endl << endl;
output << "#include <eosiolib/raw.hpp>" << endl;
output << "namespace eosio {" << endl;
generate_ident(output);
generate_current_message_ex(output);
for(const auto& type : abi.structs) {
generate_dump(output, type);
generate_current_message(output, type);
}
output << "} //eosio" << endl;
cout << output.str() << endl;
}
};
//------------------------------------------------------------
int main (int argc, char *argv[]) {
if( argc < 2 )
return 1;
auto abi = fc::json::from_file<abi_def>(argv[1]);
codegen generator(abi);
generator.generate();
return 0;
}
......@@ -16,6 +16,8 @@ set( CMAKE_CXX_STANDARD 14 )
include_directories("${CMAKE_BINARY_DIR}/contracts")
include_directories("${CMAKE_SOURCE_DIR}/contracts")
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/tests/config.hpp.in ${CMAKE_CURRENT_SOURCE_DIR}/tests/config.hpp ESCAPE_QUOTES)
file(GLOB UNIT_TESTS "chain_tests/*.cpp" "api_tests/*.cpp" "tests/abi_tests.cpp" "tests/database_tests.cpp" "tests/misc_tests.cpp" "wasm_tests/*.cpp")
add_executable( chain_test ${UNIT_TESTS} ${WASM_UNIT_TESTS} common/main.cpp )
......
......@@ -17,6 +17,8 @@
#include <eosio/chain/contracts/abi_serializer.hpp>
#include <eosio/abi_generator/abi_generator.hpp>
#include "config.hpp"
using namespace eosio;
using namespace chain;
using namespace chain::contracts;
......@@ -354,25 +356,16 @@ BOOST_AUTO_TEST_CASE(uint_types)
} FC_LOG_AND_RETHROW() }
using namespace eosio::tests::config;
BOOST_AUTO_TEST_CASE(generator)
{ try {
if( std::getenv("EOSLIB") == nullptr ) {
wlog("*************************************");
wlog("* EOSLIB env variable not defined *");
wlog("* ABIGenerator tests will not run *");
wlog("*************************************");
return;
}
struct abi_gen_helper {
auto is_abi_generation_exception =[](const eosio::abi_generation_exception& e) -> bool { return true; };
abi_gen_helper() {}
auto generate_abi = [this](const char* source, const char* abi, bool opt_sfs=false) -> bool {
const char* eosiolib_path = std::getenv("EOSLIB");
FC_ASSERT(eosiolib_path != NULL);
static bool is_abi_generation_exception(const eosio::abi_generation_exception& e) { return true; };
bool generate_abi(const char* source, const char* abi, bool opt_sfs=false) {
std::string include_param = std::string("-I") + eosiolib_path;
std::string stdcpp_include_param = std::string("-I") + eosiolib_path + "/libc++/upstream/include";
std::string stdc_include_param = std::string("-I") + eosiolib_path + "/musl/upstream/include";
......@@ -394,7 +387,12 @@ BOOST_AUTO_TEST_CASE(generator)
}
return e;
};
}
};
BOOST_FIXTURE_TEST_CASE(abigen_unknown_type, abi_gen_helper)
{ try {
const char* unknown_type = R"=====(
#include <eosiolib/types.h>
......@@ -405,7 +403,12 @@ BOOST_AUTO_TEST_CASE(generator)
};
)=====";
BOOST_CHECK_EXCEPTION( generate_abi(unknown_type, ""), eosio::abi_generation_exception, is_abi_generation_exception );
BOOST_CHECK_EXCEPTION( generate_abi(unknown_type, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_all_types, abi_gen_helper)
{ try {
const char* all_types = R"=====(
#include <eosiolib/types.hpp>
......@@ -611,6 +614,11 @@ BOOST_AUTO_TEST_CASE(generator)
)=====";
BOOST_TEST( generate_abi(all_types, all_types_abi) == true);
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_double_base, abi_gen_helper)
{ try {
const char* double_base = R"=====(
#include <eosiolib/types.h>
......@@ -627,7 +635,13 @@ BOOST_AUTO_TEST_CASE(generator)
};
)=====";
BOOST_CHECK_EXCEPTION( generate_abi(double_base, ""), eosio::abi_generation_exception, is_abi_generation_exception );
BOOST_CHECK_EXCEPTION( generate_abi(double_base, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_double_action, abi_gen_helper)
{ try {
const char* double_action = R"=====(
#include <eosiolib/types.h>
......@@ -684,6 +698,12 @@ BOOST_AUTO_TEST_CASE(generator)
BOOST_TEST( generate_abi(double_action, double_action_abi) == true );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_all_indexes, abi_gen_helper)
{ try {
const char* all_indexes = R"=====(
#include <eosiolib/types.hpp>
#include <string>
......@@ -831,6 +851,11 @@ BOOST_AUTO_TEST_CASE(generator)
BOOST_TEST( generate_abi(all_indexes, all_indexes_abi) == true );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_unable_to_determine_index, abi_gen_helper)
{ try {
const char* unable_to_determine_index = R"=====(
#include <eosiolib/types.h>
......@@ -842,10 +867,14 @@ BOOST_AUTO_TEST_CASE(generator)
)=====";
BOOST_CHECK_EXCEPTION( generate_abi(unable_to_determine_index, ""), eosio::abi_generation_exception, is_abi_generation_exception );
BOOST_CHECK_EXCEPTION( generate_abi(unable_to_determine_index, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception );
//TODO: full action / full table
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_long_field_name, abi_gen_helper)
{ try {
//TODO: full action / full table
// typedef fixed_string16 FieldName;
const char* long_field_name = R"=====(
#include <eosiolib/types.h>
......@@ -857,7 +886,12 @@ BOOST_AUTO_TEST_CASE(generator)
)=====";
BOOST_CHECK_EXCEPTION( generate_abi(long_field_name, ""), eosio::abi_generation_exception, is_abi_generation_exception );
BOOST_CHECK_EXCEPTION( generate_abi(long_field_name, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_long_type_name, abi_gen_helper)
{ try {
const char* long_type_name = R"=====(
#include <eosiolib/types.h>
......@@ -874,7 +908,12 @@ BOOST_AUTO_TEST_CASE(generator)
)=====";
BOOST_CHECK_EXCEPTION( generate_abi(long_type_name, "{}"), eosio::abi_generation_exception, is_abi_generation_exception );
BOOST_CHECK_EXCEPTION( generate_abi(long_type_name, "{}"), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_same_type_different_namespace, abi_gen_helper)
{ try {
const char* same_type_different_namespace = R"=====(
#include <eosiolib/types.h>
......@@ -895,12 +934,17 @@ BOOST_AUTO_TEST_CASE(generator)
)=====";
BOOST_CHECK_EXCEPTION( generate_abi(same_type_different_namespace, ""), eosio::abi_generation_exception, is_abi_generation_exception );
BOOST_CHECK_EXCEPTION( generate_abi(same_type_different_namespace, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_bad_index_type, abi_gen_helper)
{ try {
const char* bad_index_type = R"=====(
#include <eosiolib/types.h>
//@abi table i64
//@abi table table1 i128i128
struct table1 {
uint32_t key;
uint64_t field1;
......@@ -909,12 +953,17 @@ BOOST_AUTO_TEST_CASE(generator)
)=====";
BOOST_CHECK_EXCEPTION( generate_abi(bad_index_type, ""), eosio::abi_generation_exception, is_abi_generation_exception );
BOOST_CHECK_EXCEPTION( generate_abi(bad_index_type, "{}"), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_full_table_decl, abi_gen_helper)
{ try {
const char* full_table_decl = R"=====(
#include <eosiolib/types.hpp>
//@abi table i64
//@abi table table1 i64
class table1 {
public:
uint64_t id;
......@@ -959,6 +1008,11 @@ BOOST_AUTO_TEST_CASE(generator)
BOOST_TEST( generate_abi(full_table_decl, full_table_decl_abi) == true );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_str_table_decl, abi_gen_helper)
{ try {
const char* str_table_decl = R"=====(
#include <eosiolib/types.hpp>
#include <string>
......@@ -1004,6 +1058,10 @@ BOOST_AUTO_TEST_CASE(generator)
)=====";
BOOST_TEST( generate_abi(str_table_decl, str_table_decl_abi) == true );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_union_table, abi_gen_helper)
{ try {
const char* union_table = R"=====(
#include <eosiolib/types.h>
......@@ -1016,7 +1074,12 @@ BOOST_AUTO_TEST_CASE(generator)
)=====";
BOOST_CHECK_EXCEPTION( generate_abi(union_table, ""), eosio::abi_generation_exception, is_abi_generation_exception );
BOOST_CHECK_EXCEPTION( generate_abi(union_table, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_same_action_different_type, abi_gen_helper)
{ try {
const char* same_action_different_type = R"=====(
#include <eosiolib/types.h>
......@@ -1033,7 +1096,11 @@ BOOST_AUTO_TEST_CASE(generator)
)=====";
BOOST_CHECK_EXCEPTION( generate_abi(same_action_different_type, ""), eosio::abi_generation_exception, is_abi_generation_exception );
BOOST_CHECK_EXCEPTION( generate_abi(same_action_different_type, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_template_base, abi_gen_helper)
{ try {
const char* template_base = R"=====(
#include <eosiolib/types.h>
......@@ -1045,7 +1112,7 @@ BOOST_AUTO_TEST_CASE(generator)
typedef base<uint32_t> base32;
//@abi table i64
//@abi table table1 i64
class table1 : base32 {
public:
uint64_t id;
......@@ -1089,6 +1156,11 @@ BOOST_AUTO_TEST_CASE(generator)
BOOST_TEST( generate_abi(template_base, template_base_abi) == true );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_action_and_table, abi_gen_helper)
{ try {
const char* action_and_table = R"=====(
#include <eosiolib/types.h>
......@@ -1134,6 +1206,11 @@ BOOST_AUTO_TEST_CASE(generator)
BOOST_TEST( generate_abi(action_and_table, action_and_table_abi) == true );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_simple_typedef, abi_gen_helper)
{ try {
const char* simple_typedef = R"=====(
#include <eosiolib/types.hpp>
......@@ -1190,6 +1267,10 @@ BOOST_AUTO_TEST_CASE(generator)
)=====";
BOOST_TEST( generate_abi(simple_typedef, simple_typedef_abi) == true );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_field_typedef, abi_gen_helper)
{ try {
const char* field_typedef = R"=====(
#include <eosiolib/types.hpp>
......@@ -1264,9 +1345,248 @@ BOOST_AUTO_TEST_CASE(generator)
BOOST_TEST( generate_abi(field_typedef, field_typedef_abi) == true );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_vector_of_POD, abi_gen_helper)
{ try {
const char* abigen_vector_of_POD = R"=====(
#include <vector>
#include <string>
#include <eosiolib/types.hpp>
using namespace eosio;
using namespace std;
//@abi table
struct table1 {
uint64_t field1;
vector<uint64_t> uints64;
vector<uint32_t> uints32;
vector<uint16_t> uints16;
vector<uint8_t> uints8;
};
)=====";
const char* abigen_vector_of_POD_abi = R"=====(
{
"types": [],
"structs": [{
"name": "table1",
"base": "",
"fields": [{
"name": "field1",
"type": "uint64"
},{
"name": "uints64",
"type": "uint64[]"
},{
"name": "uints32",
"type": "uint32[]"
},{
"name": "uints16",
"type": "uint16[]"
},{
"name": "uints8",
"type": "uint8[]"
}
]
}
],
"actions": [],
"tables": [{
"name": "table1",
"index_type": "i64",
"key_names": [
"field1"
],
"key_types": [
"uint64"
],
"type": "table1"
}
]
}
)=====";
BOOST_TEST( generate_abi(abigen_vector_of_POD, abigen_vector_of_POD_abi) == true );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_vector_of_structs, abi_gen_helper)
{ try {
const char* abigen_vector_of_structs = R"=====(
#include <vector>
#include <string>
#include <eosiolib/types.hpp>
using namespace eosio;
using namespace std;
struct my_struct {
vector<uint64_t> uints64;
vector<uint32_t> uints32;
vector<uint16_t> uints16;
vector<uint8_t> uints8;
string str;
};
//@abi table
struct table1 {
uint64_t field1;
vector<my_struct> field2;
};
)=====";
const char* abigen_vector_of_structs_abi = R"=====(
{
"types": [],
"structs": [{
"name": "my_struct",
"base": "",
"fields": [{
"name": "uints64",
"type": "uint64[]"
},{
"name": "uints32",
"type": "uint32[]"
},{
"name": "uints16",
"type": "uint16[]"
},{
"name": "uints8",
"type": "uint8[]"
},{
"name": "str",
"type": "string"
}
]
},{
"name": "table1",
"base": "",
"fields": [{
"name": "field1",
"type": "uint64"
},{
"name": "field2",
"type": "my_struct[]"
}
]
}
],
"actions": [],
"tables": [{
"name": "table1",
"index_type": "i64",
"key_names": [
"field1"
],
"key_types": [
"uint64"
],
"type": "table1"
}
]
}
)=====";
BOOST_TEST( generate_abi(abigen_vector_of_structs, abigen_vector_of_structs_abi) == true );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abigen_vector_multidimension, abi_gen_helper)
{ try {
const char* abigen_vector_multidimension = R"=====(
#include <vector>
#include <string>
#include <eosiolib/types.hpp>
using namespace eosio;
using namespace std;
//@abi table
struct table1 {
uint64_t field1;
vector<vector<uint64_t>> field2;
};
)=====";
BOOST_CHECK_EXCEPTION( generate_abi(abigen_vector_multidimension, ""), eosio::abi_generation_exception, abi_gen_helper::is_abi_generation_exception );
} FC_LOG_AND_RETHROW() }
BOOST_FIXTURE_TEST_CASE(abgigen_vector_alias, abi_gen_helper)
{ try {
const char* abgigen_vector_alias = R"=====(
#include <string>
#include <vector>
#include <eosiolib/types.hpp>
#include <eosiolib/print.hpp>
using namespace std;
struct row {
std::vector<uint32_t> cells;
};
typedef vector<row> array_of_rows;
//@abi action
struct my_action {
uint64_t id;
array_of_rows rows;
};
)=====";
const char* abgigen_vector_alias_abi = R"=====(
{
"types": [{
"new_type_name": "array_of_rows",
"type": "row[]"
}
],
"structs": [{
"name": "row",
"base": "",
"fields": [{
"name": "cells",
"type": "uint32[]"
}
]
},{
"name": "my_action",
"base": "",
"fields": [{
"name": "id",
"type": "uint64"
},{
"name": "rows",
"type": "array_of_rows"
}
]
}
],
"actions": [{
"name": "myaction",
"type": "my_action"
}
],
"tables": []
}
)=====";
BOOST_TEST( generate_abi(abgigen_vector_alias, abgigen_vector_alias_abi) == true );
} FC_LOG_AND_RETHROW() }
BOOST_AUTO_TEST_CASE(general)
{ try {
......
/**
* @file
* @copyright defined in eos/LICENSE.txt
*/
namespace eosio { namespace tests { namespace config {
constexpr char eosiolib_path[] = "${CMAKE_CURRENT_SOURCE_DIR}/../contracts";
}}}
#!/bin/bash
EOSIO_INSTALL_DIR=@CMAKE_INSTALL_PREFIX@
ABIGEN=${EOSIO_INSTALL_DIR}/bin/abi_gen
CODEGEN=${EOSIO_INSTALL_DIR}/bin/codegen
ABIGEN=${EOSIO_INSTALL_DIR}/bin/eosio-abigen
BOOST_INCLUDE_DIR=@Boost_INCLUDE_DIR@
function copy_skeleton {
set -e
cp -r ${EOSIO_INSTALL_DIR}/share/skeleton/. $newname
......@@ -32,8 +31,24 @@ function build_contract {
name=`basename $file`
filePath=`dirname $file`
echo @WASM_CLANG@ -emit-llvm -O3 --std=c++14 --target=wasm32 -ffreestanding -nostdlib -fno-threadsafe-statics -fno-rtti -fno-exceptions -I ${EOSIO_INSTALL_DIR}/include -I $filePath -c $file -o $workdir/built/$name
@WASM_CLANG@ -emit-llvm -O3 --std=c++14 --target=wasm32 -ffreestanding -nostdlib -fno-threadsafe-statics -fno-rtti -fno-exceptions -I ${EOSIO_INSTALL_DIR}/include -I $filePath -c $file -o $workdir/built/$name
# echo @WASM_CLANG@ -emit-llvm -O3 --std=c++14 --target=wasm32 -nostdinc \
# -nostdlib -nostdlibinc -ffreestanding -nostdlib -fno-threadsafe-statics -fno-rtti \
# -fno-exceptions -I ${EOSIO_INSTALL_DIR}/include \
# -I${EOSIO_INSTALL_DIR}/include/libc++/upstream/include \
# -I${EOSIO_INSTALL_DIR}/include/musl/upstream/include \
# -I${BOOST_INCLUDE_DIR} \
# -I $filePath \
# -c $file -o $workdir/built/$name
@WASM_CLANG@ -emit-llvm -O3 --std=c++14 --target=wasm32 -nostdinc \
-nostdlib -nostdlibinc -ffreestanding -nostdlib -fno-threadsafe-statics -fno-rtti \
-fno-exceptions -I ${EOSIO_INSTALL_DIR}/include \
-I${EOSIO_INSTALL_DIR}/include/libc++/upstream/include \
-I${EOSIO_INSTALL_DIR}/include/musl/upstream/include \
-I${BOOST_INCLUDE_DIR} \
-I $filePath \
-c $file -o $workdir/built/$name
done
# echo @WASM_LLVM_LINK@ -o $workdir/linked.bc $workdir/built/*
......@@ -56,9 +71,13 @@ function generate_abi {
fi
context_folder=$(realpath $(dirname $1))
${ABIGEN} -extra-arg=-c -extra-arg=--std=c++14 -extra-arg=--target=wasm32 \
-extra-arg=-I${EOSIO_INSTALL_DIR}/include -extra-arg=-I$context_folder \
-extra-arg=-nostdinc -extra-arg=-nostdinc++ -extra-arg=-DABIGEN \
-extra-arg=-I${EOSIO_INSTALL_DIR}/include/libc++/upstream/include \
-extra-arg=-I${EOSIO_INSTALL_DIR}/include/musl/upstream/include \
-extra-arg=-I${BOOST_INCLUDE_DIR} \
-extra-arg=-I${EOSIO_INSTALL_DIR}/include -extra-arg=-I$context_folder \
-extra-arg=-fparse-all-comments -destination-file=${outname} -verbose=0 \
-context=$context_folder $1 --
......@@ -67,18 +86,6 @@ function generate_abi {
fi
echo "Generated ${outname} ..."
if [[ "$genserialfunctions" == "yes" ]]; then
tmp=$(basename $(realpath $1))
gen_name=${tmp%.*}.gen.hpp
${CODEGEN} ${outname} > $context_folder/${gen_name}
if [ "$?" -ne 0 ]; then
exit 1
fi
echo "Generated ${gen_name} ..."
fi
}
function print_help {
......@@ -95,12 +102,11 @@ function print_help {
echo " -o | --outname [output.wast] [input.cpp ...]"
echo " Generate the wast output file based on input cpp files"
echo " OR"
echo " -g | --genabi contract.abi [ -gs ] types.hpp"
echo " -g | --genabi contract.abi types.hpp"
echo " Generate the ABI specification file [EXPERIMENTAL]"
}
command=""
genserialfunctions="no"
while [[ $# -gt 1 ]]
do
......@@ -123,11 +129,6 @@ case $key in
shift 2
break
;;
-gs)
genserialfunctions="yes"
shift 1
break
;;
-g|--genabi)
outname="$2"
command="genabi"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册