feat support reflection
This commit is contained in:
parent
fd8ae6c6bd
commit
6566f11269
2
3rdparty/sled
vendored
2
3rdparty/sled
vendored
@ -1 +1 @@
|
||||
Subproject commit fcce11249be00ca0c7f8c2e75938de4b3e5f26da
|
||||
Subproject commit 4402688c9c63e9885de1bf99cd718150b036ac7a
|
@ -18,6 +18,8 @@ add_executable(meta
|
||||
src/types/field.cc
|
||||
src/types/method.cc
|
||||
src/registry.cc
|
||||
runtime/test.gen.cc
|
||||
runtime/reflection.gen.cc
|
||||
)
|
||||
|
||||
### add clang
|
||||
|
@ -1,60 +0,0 @@
|
||||
#pragma once
|
||||
#ifndef META_APPLY_H
|
||||
#define META_APPLY_H
|
||||
#include <functional>
|
||||
#include <tuple>
|
||||
|
||||
namespace meta {
|
||||
namespace reflection {
|
||||
namespace detail {
|
||||
template<int... Seq>
|
||||
struct Sequence {};
|
||||
|
||||
template<int N, int... Seq>
|
||||
struct MakeSeq : MakeSeq<N - 1, N - 1, Seq...> {};
|
||||
|
||||
template<int... Seq>
|
||||
struct MakeSeq<0, Seq...> {
|
||||
using type = Sequence<Seq...>;
|
||||
};
|
||||
|
||||
template<typename ReturnT, typename Func, typename Tuple, int... Seq>
|
||||
ReturnT
|
||||
ApplyImpl(const Func &func, const Tuple &tuple, const Sequence<Seq...> &)
|
||||
{
|
||||
return std::bind(func, std::get<Seq>(tuple)...)();
|
||||
}
|
||||
|
||||
struct VoidTag {};
|
||||
|
||||
}// namespace detail
|
||||
|
||||
template<typename ReturnT,
|
||||
typename Func,
|
||||
typename Tuple,
|
||||
typename std::enable_if<!std::is_void<ReturnT>::value, ReturnT>::type * = nullptr>
|
||||
ReturnT
|
||||
apply(const Func &func, const Tuple &tuple)
|
||||
{
|
||||
return detail::ApplyImpl<ReturnT>(
|
||||
func,
|
||||
tuple,
|
||||
typename detail::MakeSeq<std::tuple_size<Tuple>::value>::type());
|
||||
}
|
||||
|
||||
template<typename ReturnT = void,
|
||||
typename Func,
|
||||
typename Tuple,
|
||||
typename std::enable_if<std::is_void<ReturnT>::value, detail::VoidTag>::type * = nullptr>
|
||||
ReturnT
|
||||
apply(const Func &func, const Tuple &tuple)
|
||||
{
|
||||
return detail::ApplyImpl<ReturnT>(
|
||||
func,
|
||||
tuple,
|
||||
typename detail::MakeSeq<std::tuple_size<Tuple>::value>::type());
|
||||
}
|
||||
|
||||
}// namespace reflection
|
||||
}// namespace meta
|
||||
#endif// META_APPLY_H
|
5
runtime/reflection.gen.cc
Normal file
5
runtime/reflection.gen.cc
Normal file
@ -0,0 +1,5 @@
|
||||
#include "test.gen.h"
|
||||
|
||||
void ::meta::reflection::Registry::RegisterAll() { ::test::Test::Test_Class::Register(); }
|
||||
|
||||
void ::meta::reflection::Registry::UnregisterAll() {}
|
@ -2,7 +2,6 @@
|
||||
#ifndef META_RUNTIME_REFLECTION_H
|
||||
#define META_RUNTIME_REFLECTION_H
|
||||
#include "any.h"
|
||||
#include "apply.h"
|
||||
#include <cstdlib>
|
||||
#include <cxxabi.h>
|
||||
#include <sled/log/log.h>
|
||||
@ -42,7 +41,7 @@ RemoveTypeSpace(const std::string &str, const std::string &chars = "[]()<>*&:")
|
||||
}
|
||||
|
||||
template<typename T, typename U = typename std::decay<T>::type>
|
||||
std::string
|
||||
inline std::string
|
||||
PrettyNameImpl()
|
||||
{
|
||||
const std::string name = typeid(U).name();
|
||||
@ -71,13 +70,20 @@ PrettyName()
|
||||
#define META(...)
|
||||
#define CLASS(class_name, ...) class class_name
|
||||
#define STRUCT(struct_name, ...) struct struct_name
|
||||
#endif// __REFLECTION_PARSER_
|
||||
#endif// __REFLECTION_PARSER_ \
|
||||
|
||||
#define META_REFLECTION_BODY(class_name) \
|
||||
friend class meta::reflection::##class_name##_Method; \
|
||||
friend class meta::reflection::##class_name##_Field; \
|
||||
friend class meta::reflection::##class_name##_Constructor; \
|
||||
friend class meta::reflection::##class_name##_Serializer;
|
||||
class class_name##_Class; \
|
||||
class class_name##_Constructor; \
|
||||
class class_name##_Method; \
|
||||
class class_name##_Field; \
|
||||
class class_name##_Serializer; \
|
||||
friend class class_name##_Class; \
|
||||
friend class class_name##_Constructor; \
|
||||
friend class class_name##_Method; \
|
||||
friend class class_name##_Field; \
|
||||
friend class class_name##_Serializer; \
|
||||
friend class ::meta::reflection::Registry;
|
||||
|
||||
class Constructor;
|
||||
class Method;
|
||||
@ -113,7 +119,7 @@ public:
|
||||
typename... Params>
|
||||
inline ReturnT InvokeAndCast(void *instance, Params &&...params) const
|
||||
{
|
||||
return ::meta::reflection::any_cast<ReturnT>(InvokeImpl(instance, {¶ms...}));
|
||||
return ::meta::reflection::any_cast<ReturnT>(InvokeImpl(instance, {params...}));
|
||||
}
|
||||
|
||||
template<typename ReturnT,
|
||||
@ -121,18 +127,18 @@ public:
|
||||
typename... Params>
|
||||
inline void InvokeAndCast(void *instance, Params &&...params) const
|
||||
{
|
||||
::meta::reflection::any_cast<ReturnT>(InvokeImpl(instance, {¶ms...}));
|
||||
::meta::reflection::any_cast<ReturnT>(InvokeImpl(instance, {params...}));
|
||||
}
|
||||
|
||||
template<typename... Params>
|
||||
inline ::meta::reflection::any Invoke(void *instance, Params &&...params) const
|
||||
{
|
||||
return InvokeImpl(instance, {¶ms...});
|
||||
return InvokeImpl(instance, {params...});
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ::meta::reflection::any InvokeImpl(void *instance,
|
||||
const std::vector<void *> ¶ms) const
|
||||
virtual ::meta::reflection::any
|
||||
InvokeImpl(void *instance, const std::vector<::meta::reflection::any> ¶ms) const
|
||||
= 0;
|
||||
|
||||
private:
|
||||
@ -167,23 +173,106 @@ public:
|
||||
Class(const std::string &name, std::shared_ptr<Class> base_class = nullptr)
|
||||
: BaseType(name, base_class)
|
||||
{}
|
||||
|
||||
inline std::vector<std::shared_ptr<Class>> GetBaseClasses() const { return base_classes_; }
|
||||
|
||||
inline std::shared_ptr<Class> GetBaseClass(const std::string &name) const
|
||||
{
|
||||
auto iter = base_class_by_name_.find(name);
|
||||
if (iter != base_class_by_name_.end()) { return iter->second; }
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline std::vector<std::shared_ptr<Method>> GetMethods() const { return methods_; }
|
||||
|
||||
inline std::shared_ptr<Method> GetMethod(const std::string &name) const
|
||||
{
|
||||
auto iter = method_by_name_.find(name);
|
||||
if (iter != method_by_name_.end()) { return iter->second; }
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline std::vector<std::shared_ptr<Field>> GetFields() const { return fields_; }
|
||||
|
||||
inline std::shared_ptr<Field> GetField(const std::string &name) const
|
||||
{
|
||||
auto iter = field_by_name_.find(name);
|
||||
if (iter != field_by_name_.end()) { return iter->second; }
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
void AddBaseClass(std::shared_ptr<Class> clz)
|
||||
{
|
||||
if (base_class_by_name_.find(clz->Name()) != base_class_by_name_.end()) { return; }
|
||||
base_classes_.push_back(clz);
|
||||
base_class_by_name_[clz->Name()] = clz;
|
||||
}
|
||||
|
||||
void AddMethod(std::shared_ptr<Method> method)
|
||||
{
|
||||
if (method_by_name_.find(method->Name()) != method_by_name_.end()) { return; }
|
||||
methods_.push_back(method);
|
||||
method_by_name_[method->Name()] = method;
|
||||
}
|
||||
|
||||
void AddField(std::shared_ptr<Field> field)
|
||||
{
|
||||
fields_.push_back(field);
|
||||
field_by_name_[field->Name()] = field;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, std::shared_ptr<Class>> base_class_by_name_;
|
||||
std::unordered_map<std::string, std::shared_ptr<Method>> method_by_name_;
|
||||
std::unordered_map<std::string, std::shared_ptr<Field>> field_by_name_;
|
||||
|
||||
std::vector<std::shared_ptr<Class>> base_classes_;
|
||||
std::vector<std::shared_ptr<Method>> methods_;
|
||||
std::vector<std::shared_ptr<Field>> fields_;
|
||||
};
|
||||
|
||||
#define REFLECTION_BODY() \
|
||||
friend class meta::Serializer; \
|
||||
friend class meta::Class; \
|
||||
friend class meta::Method; \
|
||||
friend class meta::Field; \
|
||||
friend class meta::Constructor;
|
||||
|
||||
class Reflectioin {
|
||||
class Registry {
|
||||
public:
|
||||
static Reflectioin *Instance();
|
||||
~Reflectioin();
|
||||
std::shared_ptr<Class> GetClass();
|
||||
// std::shared_ptr<Constructor> GetConstructor(std::shared_ptr<Class> clz);
|
||||
std::shared_ptr<Method> GetMethod(std::shared_ptr<Class> clz);
|
||||
std::shared_ptr<Field> GetField(std::shared_ptr<Class> clz);
|
||||
static Registry *Instance()
|
||||
{
|
||||
static Registry instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
~Registry() {}
|
||||
|
||||
static void RegisterAll();
|
||||
static void UnregisterAll();
|
||||
|
||||
static std::shared_ptr<Class> GetClass(const std::string &name)
|
||||
{
|
||||
return Instance()->GetClassInner(name);
|
||||
}
|
||||
|
||||
static void RegisterClass(std::shared_ptr<Class> clz) { Instance()->RegisterClassInner(clz); }
|
||||
|
||||
static std::vector<std::shared_ptr<Class>> GetClasses() { return Instance()->classes(); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<Class> GetClassInner(const std::string &name) const
|
||||
{
|
||||
auto iter = class_by_name_.find(name);
|
||||
if (iter != class_by_name_.end()) { return iter->second; }
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline void RegisterClassInner(std::shared_ptr<Class> clz)
|
||||
{
|
||||
if (class_by_name_.find(clz->Name()) != class_by_name_.end()) { return; }
|
||||
classes_.push_back(clz);
|
||||
class_by_name_[clz->Name()] = clz;
|
||||
}
|
||||
|
||||
inline std::vector<std::shared_ptr<Class>> classes() const { return classes_; }
|
||||
|
||||
std::unordered_map<std::string, std::shared_ptr<Class>> class_by_name_;
|
||||
std::vector<std::shared_ptr<Class>> classes_;
|
||||
};
|
||||
}// namespace reflection
|
||||
|
||||
|
90
runtime/test.gen.cc
Normal file
90
runtime/test.gen.cc
Normal file
@ -0,0 +1,90 @@
|
||||
#include "test.gen.h"
|
||||
#include <memory>
|
||||
|
||||
/**
|
||||
* Class
|
||||
**/
|
||||
test::Test::Test_Class::Test_Class()
|
||||
: ::meta::reflection::Class("test::Test", nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void test::Test::Test_Class::Register() {
|
||||
auto self = new test::Test::Test_Class();
|
||||
auto clz = std::shared_ptr<::meta::reflection::Class>(self);
|
||||
// self->AddBaseClassProxy();
|
||||
|
||||
self->AddMethod(std::make_shared<test::Test::Test_Method>("size", clz));
|
||||
self->AddMethod(std::make_shared<test::Test::Test_Method>("length", clz));
|
||||
|
||||
self->AddField(std::make_shared<test::Test::Test_Field>("length_", clz));
|
||||
self->AddField(std::make_shared<test::Test::Test_Field>("size_", clz));
|
||||
|
||||
::meta::reflection::Registry::Instance()->RegisterClass(clz);
|
||||
}
|
||||
void test::Test::Test_Class::AddBaseClassProxy(std::shared_ptr<::meta::reflection::Class> base) {
|
||||
AddBaseClass(base);
|
||||
}
|
||||
void test::Test::Test_Class::AddMethodProxy(std::shared_ptr<::meta::reflection::Method> method) {
|
||||
AddMethod(method);
|
||||
}
|
||||
void test::Test::Test_Class::AddFieldProxy(std::shared_ptr<::meta::reflection::Field> field) {
|
||||
AddField(field);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Field
|
||||
**/
|
||||
|
||||
test::Test::Test_Field::Test_Field(
|
||||
const std::string& name,
|
||||
std::shared_ptr<::meta::reflection::Class> parent)
|
||||
: ::meta::reflection::Field(name, parent) {}
|
||||
|
||||
::meta::reflection::any test::Test::Test_Field::GetImpl(void* instance) const {
|
||||
::test::Test* obj = (::test::Test*)instance;
|
||||
|
||||
if (strcmp(Name().c_str(), "length_") == 0) {
|
||||
return obj->length_;
|
||||
}
|
||||
if (strcmp(Name().c_str(), "size_") == 0) {
|
||||
return obj->size_;
|
||||
}
|
||||
return ::meta::reflection::any{};
|
||||
}
|
||||
|
||||
void test::Test::Test_Field::SetImpl(void* instance, const ::meta::reflection::any& value) const {
|
||||
::test::Test* obj = (::test::Test*)instance;
|
||||
if(strcmp(Name().c_str(), "length_") == 0) { obj->length_ = ::meta::reflection::any_cast<int>(value);}
|
||||
if(strcmp(Name().c_str(), "size_") == 0) { obj->size_ = ::meta::reflection::any_cast<int>(value);}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Method
|
||||
**/
|
||||
test::Test::Test_Method::Test_Method(
|
||||
const std::string& name,
|
||||
std::shared_ptr<::meta::reflection::Class> parent)
|
||||
: ::meta::reflection::Method(name, parent) {}
|
||||
|
||||
::meta::reflection::any test::Test::Test_Method::InvokeImpl(void* instance, const std::vector<::meta::reflection::any> ¶ms) const {
|
||||
::test::Test* obj = (::test::Test*)instance;
|
||||
|
||||
if (strcmp(Name().c_str(), "size") == 0) {
|
||||
return
|
||||
obj->
|
||||
size(
|
||||
);
|
||||
}
|
||||
if (strcmp(Name().c_str(), "length") == 0) {
|
||||
return
|
||||
obj->
|
||||
length(
|
||||
);
|
||||
}
|
||||
return ::meta::reflection::any{};
|
||||
}
|
||||
|
41
runtime/test.gen.h
Normal file
41
runtime/test.gen.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
#ifndef META_GEN_Test_PROXY_H
|
||||
#define META_GEN_Test_PROXY_H
|
||||
|
||||
#include "test.h"
|
||||
|
||||
// namespace meta {
|
||||
// namespace reflection {
|
||||
|
||||
class ::test::Test::Test_Class : public ::meta::reflection::Class {
|
||||
public:
|
||||
Test_Class();
|
||||
static void Register();
|
||||
private:
|
||||
void AddBaseClassProxy(std::shared_ptr<::meta::reflection::Class> base) ;
|
||||
void AddMethodProxy(std::shared_ptr<::meta::reflection::Method> method) ;
|
||||
void AddFieldProxy(std::shared_ptr<::meta::reflection::Field> field) ;
|
||||
};
|
||||
|
||||
class ::test::Test::Test_Field : public ::meta::reflection::Field {
|
||||
public:
|
||||
Test_Field(const std::string& name, std::shared_ptr<::meta::reflection::Class> parent);
|
||||
|
||||
protected:
|
||||
::meta::reflection::any GetImpl(void* instance) const override;
|
||||
void SetImpl(void* instance, const ::meta::reflection::any& value) const override;
|
||||
};
|
||||
|
||||
class ::test::Test::Test_Method : public ::meta::reflection::Method {
|
||||
public:
|
||||
Test_Method(const std::string& name, std::shared_ptr<::meta::reflection::Class> parent);
|
||||
|
||||
protected:
|
||||
::meta::reflection::any InvokeImpl(void* instance, const std::vector<::meta::reflection::any> ¶ms) const override;
|
||||
};
|
||||
|
||||
// } // namespace reflection
|
||||
// } // namespace meta
|
||||
|
||||
#endif // META_GEN_Test_PROXY_H
|
||||
|
@ -3,38 +3,25 @@
|
||||
#define META_RUNTIME_TEST_H
|
||||
|
||||
#include "reflection.h"
|
||||
#include <vector>
|
||||
|
||||
namespace test {
|
||||
class TypeDef {};
|
||||
|
||||
CLASS(Test)
|
||||
{
|
||||
META_REFLECTION_BODY(Test);
|
||||
|
||||
public:
|
||||
META("Constructor")
|
||||
Test() : b_(0), a_(0) {}
|
||||
Test() {}
|
||||
|
||||
Test(int a) : b_(0), a_(a) {}
|
||||
|
||||
META("Test")
|
||||
int GetA() const { return a_; }
|
||||
|
||||
int kk(int, void *);
|
||||
TypeDef GetTypeDef() const { return type_def_; }
|
||||
const size_t size() const { return size_; }
|
||||
const size_t length() const { return length_; }
|
||||
|
||||
private:
|
||||
struct Void {};
|
||||
META("1")
|
||||
int length_;
|
||||
|
||||
STRUCT(VoidMeta, "VoidMeta")
|
||||
{
|
||||
META("Enable")
|
||||
int a;
|
||||
};
|
||||
|
||||
const int b_;
|
||||
int a_;
|
||||
|
||||
META("TypeDef")
|
||||
TypeDef type_def_;
|
||||
META("2")
|
||||
int size_;
|
||||
};
|
||||
|
||||
}// namespace test
|
||||
|
@ -59,6 +59,7 @@ Parser::Parse(const std::string &file_name, std::vector<const char *> extra_args
|
||||
|
||||
// ignore error for reflection.h
|
||||
if (sled::EndsWith(filename, "reflection.h")) { continue; }
|
||||
if (sled::EndsWith(filename, "any.h")) { continue; }
|
||||
|
||||
LOGE("parser", "diagnostic: {}", msg);
|
||||
}
|
||||
|
@ -39,19 +39,38 @@ BaseGenerator::GenClassRenderData(Class *clz, inja::json &class_def)
|
||||
class_def["properties"] = inja::json::array();
|
||||
for (auto &prop : clz->properties()) { class_def["properties"].push_back(prop); }
|
||||
|
||||
inja::json constructors = inja::json::array();
|
||||
inja::json methods = inja::json::array();
|
||||
inja::json fields = inja::json::array();
|
||||
|
||||
GenClassConstructorRenderData(clz, constructors);
|
||||
GenClassMethodRenderData(clz, methods);
|
||||
GenClassFieldRenderData(clz, fields);
|
||||
|
||||
class_def["class_constructors"] = constructors;
|
||||
class_def["class_methods"] = methods;
|
||||
class_def["class_fields"] = fields;
|
||||
}
|
||||
|
||||
void
|
||||
BaseGenerator::GenClassConstructorRenderData(Class *clz, inja::json &constructor_defs)
|
||||
{}
|
||||
{
|
||||
for (auto &constructor : clz->constructors()) {
|
||||
inja::json constructor_def;
|
||||
constructor_def["name"] = constructor->Name();
|
||||
constructor_def["properties"] = inja::json::array();
|
||||
for (auto &prop : constructor->properties()) {
|
||||
constructor_def["properties"].push_back(prop);
|
||||
}
|
||||
inja::json params = inja::json::array();
|
||||
for (auto ¶m : constructor->arguments()) {
|
||||
inja::json param_def;
|
||||
param_def["name"] = "";
|
||||
param_def["type"] = param.GetDisplayName();
|
||||
params.push_back(param_def);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BaseGenerator::GenClassFieldRenderData(Class *clz, inja::json &field_defs)
|
||||
@ -60,6 +79,7 @@ BaseGenerator::GenClassFieldRenderData(Class *clz, inja::json &field_defs)
|
||||
inja::json field_def;
|
||||
field_def["name"] = field->Name();
|
||||
field_def["is_const"] = field->IsConst();
|
||||
field_def["is_static"] = field->IsStatic();
|
||||
field_def["properties"] = inja::json::array();
|
||||
for (auto &prop : field->properties()) { field_def["properties"].push_back(prop); }
|
||||
field_def["type"] = field->cursor().GetType().GetDisplayName();
|
||||
@ -73,9 +93,10 @@ BaseGenerator::GenClassMethodRenderData(Class *clz, inja::json &method_defs)
|
||||
for (auto &method : clz->methods()) {
|
||||
inja::json method_def;
|
||||
method_def["name"] = method->Name();
|
||||
method_def["is_const"] = method->IsConst();
|
||||
method_def["is_static"] = method->IsStatic();
|
||||
method_def["properties"] = inja::json::array();
|
||||
for (auto &prop : method->properties()) { method_def["properties"].push_back(prop); }
|
||||
method_def["is_const"] = method->IsConst();
|
||||
method_def["return_type"] = method->return_type().GetDisplayName();
|
||||
inja::json params = inja::json::array();
|
||||
for (auto ¶m : method->arguments()) {
|
||||
|
151
src/main.cc
151
src/main.cc
@ -1,6 +1,7 @@
|
||||
#include "generators/base_generator.h"
|
||||
#include "reflection.h"
|
||||
#include "registry.h"
|
||||
#include "test.gen.h"
|
||||
#include "types/class.h"
|
||||
#include "clang/parser.h"
|
||||
#include <fstream>
|
||||
@ -15,12 +16,13 @@ const char *kTag = "main";
|
||||
|
||||
class Generator : public meta::BaseGenerator {
|
||||
public:
|
||||
Generator(const std::string &template_path)
|
||||
Generator(const std::string &template_path, const std::string &output_path = "")
|
||||
{
|
||||
std::fstream in(template_path, std::ios::in);
|
||||
std::stringstream ss;
|
||||
ss << in.rdbuf();
|
||||
template_ = ss.str();
|
||||
output_path_ = output_path;
|
||||
}
|
||||
|
||||
~Generator() override = default;
|
||||
@ -33,9 +35,51 @@ public:
|
||||
inja::Environment env;
|
||||
env.set_trim_blocks(true);
|
||||
env.set_lstrip_blocks(true);
|
||||
env.add_callback("to_upper", 1, [](inja::Arguments &args) {
|
||||
return sled::ToUpper(args.at(0)->get<std::string>());
|
||||
});
|
||||
env.add_callback("to_lower", 1, [](inja::Arguments &args) {
|
||||
return sled::ToLower(args.at(0)->get<std::string>());
|
||||
});
|
||||
// CamelCase or SnakeCase to SnakeCase
|
||||
env.add_callback("to_snake_case", 1, [](inja::Arguments &args) {
|
||||
const std::string str = args.at(0)->get<std::string>();
|
||||
std::string result;
|
||||
for (size_t i = 0; i < str.size(); i++) {
|
||||
if (i > 0 && str[i] >= 'A' && str[i] <= 'Z') { result.push_back('_'); }
|
||||
result.push_back(sled::ToLower(str[i]));
|
||||
}
|
||||
return result;
|
||||
});
|
||||
env.add_callback("to_camel_case", 1, [](inja::Arguments &args) {
|
||||
const std::string str = args.at(0)->get<std::string>();
|
||||
std::string result;
|
||||
bool to_upper = false;
|
||||
for (size_t i = 0; i < str.size(); i++) {
|
||||
if (str[i] == '_') {
|
||||
to_upper = true;
|
||||
} else {
|
||||
if (to_upper) {
|
||||
result.push_back(sled::ToUpper(str.substr(i, 1))[0]);
|
||||
to_upper = false;
|
||||
} else {
|
||||
result.push_back(str[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
try {
|
||||
LOGV(kTag, "data={}", class_def.dump());
|
||||
LOGV(kTag, "class_def={}", env.render(template_, class_def));
|
||||
std::string result = env.render(template_, class_def);
|
||||
if (output_path_.empty()) {
|
||||
LOGI(kTag, "render_result=\n{}", result);
|
||||
} else {
|
||||
std::ofstream out(output_path_);
|
||||
out << result;
|
||||
}
|
||||
|
||||
} catch (const std::exception &e) {
|
||||
LOGE(kTag, "error: {}", e.what());
|
||||
}
|
||||
@ -44,88 +88,14 @@ public:
|
||||
|
||||
private:
|
||||
std::string template_;
|
||||
std::string output_path_;
|
||||
};
|
||||
|
||||
// template<typename ClassT, typename ReturnT = void, typename... Args>
|
||||
// std::function<void(sled::any)>
|
||||
// MemberFunctionWrapper(void (ClassT::*func)(Args...))
|
||||
// {
|
||||
// return [=](sled::any obj_args) {
|
||||
// using tuple = ::std::tuple<ClassT *, Args...>;
|
||||
// // ::std::tuple<ClassT *, Args...> *pTuple = ::sled::any_cast<tuple *>(obj_args);
|
||||
// auto tuple_ptr = ::sled::any_cast<tuple *>(obj_args);
|
||||
// sled::apply(func, *tuple_ptr);
|
||||
// };
|
||||
// }
|
||||
|
||||
template<typename ClassT, typename ReturnT, typename... Args>
|
||||
std::function<ReturnT(sled::any)>
|
||||
MemberFunctionWrapper(ReturnT (ClassT::*func)(Args...))
|
||||
{
|
||||
return [=](sled::any obj_args) {
|
||||
using tuple = ::std::tuple<ClassT *, Args...>;
|
||||
// ::std::tuple<ClassT *, Args...> *pTuple = ::sled::any_cast<tuple *>(obj_args);
|
||||
auto tuple_ptr = ::sled::any_cast<tuple *>(obj_args);
|
||||
return sled::apply<ReturnT>(func, *tuple_ptr);
|
||||
};
|
||||
}
|
||||
|
||||
class Test {
|
||||
public:
|
||||
void Show(int a, double b, std::string c) { LOGV(kTag, "a={}, b={}, c={}", a, b, c); }
|
||||
|
||||
// int Show(int a, int b, const std::string &c)
|
||||
// {
|
||||
// LOGV(kTag, "a={}, b={}, c={}", a, b, c);
|
||||
// return 0;
|
||||
// }
|
||||
};
|
||||
|
||||
class Adder {
|
||||
public:
|
||||
int Add(int a, int b) { return a + b; }
|
||||
friend class meta::reflection::Method;
|
||||
};
|
||||
|
||||
// Add(int, int)
|
||||
class AdderMethod : public meta::reflection::Method {
|
||||
public:
|
||||
AdderMethod(const std::string &name, std::shared_ptr<meta::reflection::Class> parent)
|
||||
: meta::reflection::Method(name, parent)
|
||||
{
|
||||
fun_ = MemberFunctionWrapper<Adder, int, int, int>(&Adder::Add);
|
||||
}
|
||||
|
||||
int Add(int a, int b) { return a + b; }
|
||||
|
||||
protected:
|
||||
meta::reflection::any InvokeImpl(void *instance,
|
||||
const std::vector<void *> ¶ms) const override
|
||||
{
|
||||
Adder *adder = reinterpret_cast<Adder *>(instance);
|
||||
using tuple = std::tuple<int, int>;
|
||||
auto t = std::make_tuple(adder,
|
||||
*reinterpret_cast<int *>(params[0]),
|
||||
*reinterpret_cast<int *>(params[1]));
|
||||
return fun_(&t);
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<int(sled::any)> fun_;
|
||||
};
|
||||
void TestFunc();
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
auto clz = std::make_shared<meta::reflection::Class>("Test");
|
||||
class Adder adder;
|
||||
meta::reflection::Method *method = new AdderMethod("Add", clz);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
LOGV("", "{}+{}={}", i, i, meta::reflection::any_cast<int>(method->Invoke(&adder, i, i)));
|
||||
}
|
||||
|
||||
void (Test::*p)(int, double, std::string) = &Test::Show;
|
||||
|
||||
LOGV(kTag, "{}", meta::reflection::PrettyName<meta::Registry>());
|
||||
// LOGI(kTag, "cwd={}", sled::Path::Current().ToString());
|
||||
meta::Parser parser;
|
||||
@ -151,10 +121,31 @@ main(int argc, char *argv[])
|
||||
LOGI(kTag, "{}\n{}", meta::Registry::Instance()->GetQualifiedName(clz), clz->ToString());
|
||||
}
|
||||
|
||||
Generator generator1("template/class_proxy_include.inja");
|
||||
Generator generator1("template/class_proxy_include.inja", "runtime/test.gen.h");
|
||||
generator1.Generate();
|
||||
Generator generator2("template/class_proxy_source.inja");
|
||||
Generator generator2("template/class_proxy_source.inja", "runtime/test.gen.cc");
|
||||
generator2.Generate();
|
||||
|
||||
::meta::reflection::Registry::RegisterAll();
|
||||
TestFunc();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
TestFunc()
|
||||
{
|
||||
auto clz = ::meta::reflection::Registry::Instance()->GetClass("test::Test");
|
||||
if (clz) {
|
||||
LOGI(kTag, "class={}", clz->Name());
|
||||
::test::Test test;
|
||||
auto size_method = clz->GetMethod("size");
|
||||
auto size_field = clz->GetField("size_");
|
||||
for (int i = 0; i < 10; i++) {
|
||||
size_field->Set(&test, i);
|
||||
LOGI(kTag, "size_field={}", size_field->GetAndCast<int>(&test));
|
||||
LOGI(kTag, "size_invoke={}", size_method->InvokeAndCast<size_t>(&test));
|
||||
}
|
||||
} else {
|
||||
LOGE(kTag, "class not found");
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,18 @@ Field::Field(const Cursor &cursor, const std::vector<std::string> &namespaces, c
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Field::IsConst() const
|
||||
{
|
||||
return cursor().GetType().IsConst();
|
||||
}
|
||||
|
||||
bool
|
||||
Field::IsStatic() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string
|
||||
Field::ToString() const
|
||||
{
|
||||
|
@ -11,6 +11,8 @@ public:
|
||||
Field(const Cursor &cursor, const std::vector<std::string> &namespaces, const Class &parent);
|
||||
|
||||
~Field() override = default;
|
||||
bool IsConst() const override;
|
||||
bool IsStatic() const;
|
||||
|
||||
std::string ToString() const override;
|
||||
std::string TypeName() const override;
|
||||
|
@ -46,4 +46,10 @@ Method::IsConst() const
|
||||
return clang_CXXMethod_isConst(cursor_.handle());
|
||||
};
|
||||
|
||||
bool
|
||||
Method::IsStatic() const
|
||||
{
|
||||
return clang_CXXMethod_isStatic(cursor().handle());
|
||||
}
|
||||
|
||||
}// namespace meta
|
||||
|
@ -14,6 +14,7 @@ public:
|
||||
std::string TypeName() const override;
|
||||
|
||||
bool IsConst() const override;
|
||||
bool IsStatic() const;
|
||||
|
||||
CursorType return_type() const { return return_type_; }
|
||||
|
||||
|
@ -2,15 +2,22 @@
|
||||
#ifndef META_GEN_{{class_name}}_PROXY_H
|
||||
#define META_GEN_{{class_name}}_PROXY_H
|
||||
|
||||
#include "runtime/reflection.h"
|
||||
#include "test.h"
|
||||
|
||||
namespace meta {
|
||||
namespace reflection {
|
||||
// namespace meta {
|
||||
// namespace reflection {
|
||||
|
||||
class {{class_name}}_Class : public ::meta::reflection::Class {
|
||||
class ::{{class_namespace}}::{{class_name}}::{{class_name}}_Class : public ::meta::reflection::Class {
|
||||
public:
|
||||
{{class_name}}_Class();
|
||||
static void Register();
|
||||
private:
|
||||
void AddBaseClassProxy(std::shared_ptr<::meta::reflection::Class> base) ;
|
||||
void AddMethodProxy(std::shared_ptr<::meta::reflection::Method> method) ;
|
||||
void AddFieldProxy(std::shared_ptr<::meta::reflection::Field> field) ;
|
||||
};
|
||||
|
||||
class {{class_name}}_Field : public ::meta::reflection::Field {
|
||||
class ::{{class_namespace}}::{{class_name}}::{{class_name}}_Field : public ::meta::reflection::Field {
|
||||
public:
|
||||
{{class_name}}_Field(const std::string& name, std::shared_ptr<::meta::reflection::Class> parent);
|
||||
|
||||
@ -19,16 +26,16 @@ protected:
|
||||
void SetImpl(void* instance, const ::meta::reflection::any& value) const override;
|
||||
};
|
||||
|
||||
class {{class_name}}_Method : public ::meta::reflection::Method {
|
||||
class ::{{class_namespace}}::{{class_name}}::{{class_name}}_Method : public ::meta::reflection::Method {
|
||||
public:
|
||||
{{class_name}}_Method(const std::string& name, std::shared_ptr<::meta::reflection::Class> parent);
|
||||
|
||||
protected:
|
||||
::meta::reflection::any InvokeImpl(void* instance, const std::vector<void *> ¶ms) const override;
|
||||
::meta::reflection::any InvokeImpl(void* instance, const std::vector<::meta::reflection::any> ¶ms) const override;
|
||||
};
|
||||
|
||||
} // namespace reflection
|
||||
} // namespace meta
|
||||
// } // namespace reflection
|
||||
// } // namespace meta
|
||||
|
||||
#endif // META_GEN_{{class_name}}_PROXY_H
|
||||
|
||||
|
@ -1,31 +1,69 @@
|
||||
#include "{{class_name}}.gen.h"
|
||||
#include <string.h>
|
||||
#include "{{to_lower(class_name)}}.gen.h"
|
||||
#include <memory>
|
||||
|
||||
/**
|
||||
* Class
|
||||
**/
|
||||
{{class_namespace}}::{{class_name}}::{{class_name}}_Class::{{class_name}}_Class()
|
||||
: ::meta::reflection::Class("{{class_namespace}}::{{class_name}}", nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void {{class_namespace}}::{{class_name}}::{{class_name}}_Class::Register() {
|
||||
auto self = new {{class_namespace}}::{{class_name}}::{{class_name}}_Class();
|
||||
auto clz = std::shared_ptr<::meta::reflection::Class>(self);
|
||||
// self->AddBaseClassProxy();
|
||||
|
||||
{% for method in class_methods %}
|
||||
self->AddMethod(std::make_shared<{{class_namespace}}::{{class_name}}::{{class_name}}_Method>("{{method.name}}", clz));
|
||||
{% endfor %}
|
||||
|
||||
{% for field in class_fields %}
|
||||
self->AddField(std::make_shared<{{class_namespace}}::{{class_name}}::{{class_name}}_Field>("{{field.name}}", clz));
|
||||
{% endfor %}
|
||||
|
||||
::meta::reflection::Registry::Instance()->RegisterClass(clz);
|
||||
}
|
||||
void {{class_namespace}}::{{class_name}}::{{class_name}}_Class::AddBaseClassProxy(std::shared_ptr<::meta::reflection::Class> base) {
|
||||
AddBaseClass(base);
|
||||
}
|
||||
void {{class_namespace}}::{{class_name}}::{{class_name}}_Class::AddMethodProxy(std::shared_ptr<::meta::reflection::Method> method) {
|
||||
AddMethod(method);
|
||||
}
|
||||
void {{class_namespace}}::{{class_name}}::{{class_name}}_Class::AddFieldProxy(std::shared_ptr<::meta::reflection::Field> field) {
|
||||
AddField(field);
|
||||
}
|
||||
|
||||
namespace meta {
|
||||
namespace reflection {
|
||||
|
||||
/**
|
||||
* Field
|
||||
**/
|
||||
|
||||
{{class_name}}_Field::{{class_name}}_Field(
|
||||
{{class_namespace}}::{{class_name}}::{{class_name}}_Field::{{class_name}}_Field(
|
||||
const std::string& name,
|
||||
std::shared_ptr<::meta::reflection::Class> parent)
|
||||
: ::meta::reflection::Field(name, parent) {}
|
||||
|
||||
::meta::reflection::any GetImpl(void* instance) const {
|
||||
::meta::reflection::any {{class_namespace}}::{{class_name}}::{{class_name}}_Field::GetImpl(void* instance) const {
|
||||
::{{class_namespace}}::{{class_name}}* obj = (::{{class_namespace}}::{{class_name}}*)instance;
|
||||
|
||||
{% for field in class_fields %}
|
||||
if (strcmp(name().c_str(), "{{field.name}}") == 0) { return obj->{{field.name}}; }
|
||||
if (strcmp(Name().c_str(), "{{field.name}}") == 0) {
|
||||
{% if field.is_static %}
|
||||
return ::{{class_namespace}}::{{class_name}}::{{field.name}};
|
||||
{% else %}
|
||||
return obj->{{field.name}};
|
||||
{% endif %}
|
||||
}
|
||||
{% endfor %}
|
||||
return ::meta::reflection::any{};
|
||||
}
|
||||
|
||||
void SetImpl(void* instance, const ::meta::reflection::any& value) const {
|
||||
void {{class_namespace}}::{{class_name}}::{{class_name}}_Field::SetImpl(void* instance, const ::meta::reflection::any& value) const {
|
||||
::{{class_namespace}}::{{class_name}}* obj = (::{{class_namespace}}::{{class_name}}*)instance;
|
||||
{% for field in class_fields %}
|
||||
{% if not field.is_const %}
|
||||
if(strcmp(name().c_str(), "{{field.name}}") == 0) { obj->{{field.name}} = value.as<{{field.type}}>();}
|
||||
if(strcmp(Name().c_str(), "{{field.name}}") == 0) { obj->{{field.name}} = ::meta::reflection::any_cast<{{field.type}}>(value);}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
@ -35,44 +73,42 @@ void SetImpl(void* instance, const ::meta::reflection::any& value) const {
|
||||
/**
|
||||
* Method
|
||||
**/
|
||||
{{class_name}}_Method::{{class_name}}_Method(
|
||||
{{class_namespace}}::{{class_name}}::{{class_name}}_Method::{{class_name}}_Method(
|
||||
const std::string& name,
|
||||
std::shared_ptr<::meta::reflection::Class> parent)
|
||||
: ::meta::reflection::Method(name, parent) {}
|
||||
|
||||
::meta::reflection::any InvokeImpl(void* instance, const std::vector<void *> ¶ms) const {
|
||||
::meta::reflection::any {{class_namespace}}::{{class_name}}::{{class_name}}_Method::InvokeImpl(void* instance, const std::vector<::meta::reflection::any> ¶ms) const {
|
||||
::{{class_namespace}}::{{class_name}}* obj = (::{{class_namespace}}::{{class_name}}*)instance;
|
||||
|
||||
{% for method in class_methods %}
|
||||
{# start if(, else if(, #}
|
||||
{% if loop.is_first %}
|
||||
if (strcmp(name.c_str(), "{{method.name}}") == 0) {
|
||||
{% else %}
|
||||
} else if (strcmp(name.c_str(), "{{method.name}}") == 0) {
|
||||
{% endif %}
|
||||
|
||||
if (strcmp(Name().c_str(), "{{method.name}}") == 0) {
|
||||
{% if method.return_type != "void" %}
|
||||
return obj->{{method.name}}(
|
||||
return
|
||||
{% if method.is_static %}
|
||||
::{{class_namespace}}::{{class_name}}::
|
||||
{% else %}
|
||||
obj->
|
||||
{% endif %}{{method.name}}(
|
||||
{% for param in method.params%}
|
||||
*({{param.type}}*)params[{{loop.index}}]{% if not loop.is_last %}, {% endif %}
|
||||
::meta::reflection::any_cast<{{param.type}}>(params[{{loop.index}}]){% if not loop.is_last %}, {% endif %}
|
||||
{% endfor %}
|
||||
);
|
||||
{% else %}
|
||||
obj->{{method.name}}(
|
||||
{% if method.is_static %}
|
||||
::{{class_namespace}}::{{class_name}}::
|
||||
{% else %}
|
||||
obj->
|
||||
{%endif%}}
|
||||
{{method.name}}(
|
||||
{% for param in method.params%}
|
||||
*({{param.type}}*)params[{{loop.index}}]{% if not loop.last %}, {% endif %}
|
||||
::meta::reflection::any_cast<{{param.type}}>(params[{{loop.index}}]){% if not loop.last %}, {% endif %}
|
||||
{% endfor %}
|
||||
);
|
||||
return;
|
||||
return ::meta::reflection::any{};
|
||||
{% endif %}
|
||||
|
||||
{% if loop.is_last %}
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
{% endfor %}
|
||||
return ::meta::reflection::any{};
|
||||
}
|
||||
|
||||
} // namespace reflection
|
||||
} // namespace meta
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user