feat use inja generate

This commit is contained in:
tqcq 2024-03-04 18:21:58 +08:00
parent ab434df5fc
commit fd8ae6c6bd
26 changed files with 30494 additions and 1384 deletions

4753
3rdparty/inja/inja.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

24765
3rdparty/inja/nlohmann/json.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2
3rdparty/sled vendored

@ -1 +1 @@
Subproject commit f31657640f5731c2f86206190fe1d59728225795
Subproject commit fcce11249be00ca0c7f8c2e75938de4b3e5f26da

View File

@ -41,5 +41,6 @@ endif()
target_include_directories(meta PRIVATE
${CLANG_INCLUDE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/mustache)
${CMAKE_CURRENT_SOURCE_DIR}/runtime
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/inja)
target_link_libraries(meta PRIVATE sled ${CLANG_LIB_LIBRARIES})

329
runtime/any.h Normal file
View File

@ -0,0 +1,329 @@
/**
* Port of boost::any for C++11 compilers.
* See http://www.boost.org/libs/any for Documentation.
*
* See also:
* + http://en.cppreference.com/w/cpp/any
* + http://en.cppreference.com/w/cpp/experimental/any
* + http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4562.html#any
* + https://cplusplus.github.io/LWG/lwg-active.html#2509
*
* Copyright Kevlin Henney, 2000, 2001, 2002. All rights reserved.
* Copyright Claudio Fantacci, 2018. All rights reserved.
*
* what: variant type boost::any
* who: contributed by Kevlin Henney,
* with features contributed and bugs found by Antony Polukhin, Ed Brey, Mark Rodgers, Peter Dimov and James Curran,
* with C++11 compiler port by Claudio Fantacci
* when: July 2001, April 2013 - May 2013, September 2018
*
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE.md or copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#pragma once
#ifndef META_ANY_H
#define META_ANY_H
#include <algorithm>
#include <memory>
#include <stdexcept>
#include <type_traits>
#include <typeinfo>
namespace meta {
namespace reflection {
/**
* The class any describes a type-safe container for single values of any type.
* An object of class any stores an instance of any type that satisfies the
* constructor requirements or is empty, and this is referred to as the state
* of the class any object. The stored instance is called the contained object.
* Two states are equivalent if they are either both empty or if both are not
* empty and if the contained objects are equivalent.
* The non-member any_cast functions provide type-safe access to the contained object.
*/
class any final {
public:
/**
* Constructs an empty object.
*/
any() noexcept : content(0) {}
/**
* Copies content of other into a new instance, so that any content is equivalent
* in both type and value to those of other prior to the constructor call,
* or empty if other is empty.
*/
any(const any &other) : content(other.content ? other.content->clone() : 0) {}
/**
* Moves content of other into a new instance, so that any content is equivalent
* in both type and value to those of other prior to the constructor call,
* or empty if other is empty.
*/
any(any &&other) noexcept : content(other.content) { other.content = 0; }
/**
* Constructs an object with initial content an object of type std::decay_t<ValueType>,
* direct-initialized from std::forward<ValueType>(value). If
* std::is_copy_constructible<std::decay_t<ValueType>>::value is false, the program is ill-formed.
*/
template<typename ValueType>
any(const ValueType &value)
: content(
new holder<typename std::remove_cv<typename std::decay<const ValueType>::type>::type>(
value))
{}
/**
* Constructs an object with initial content an object of type std::decay_t<ValueType>,
* direct-initialized from std::forward<ValueType>(value). If
* std::is_copy_constructible<std::decay_t<ValueType>>::value is false, the program is ill-formed.
*/
template<typename ValueType>
any(ValueType &&value,
typename std::enable_if<!std::is_same<any &, ValueType>::value>::type * = 0,
typename std::enable_if<!std::is_const<ValueType>::value>::type * = 0)
: content(
new holder<typename std::decay<ValueType>::type>(static_cast<ValueType &&>(value)))
{}
/**
* Destruct the object.
*/
~any() noexcept { delete content; }
/**
* Assigns contents to the contained value.
* Assigns by copying the state of rhs, as if by any(rhs).swap(*this).
*
* @param rhs object whose contained value to assign
*/
any &operator=(const any &rhs)
{
any(rhs).swap(*this);
return *this;
}
/**
* Assigns contents to the contained value.
* Assigns by moving the state of rhs, as if by any(std::move(rhs)).swap(*this).
* rhs is left in a valid but unspecified state after the assignment.
*
* @param rhs object whose contained value to assign
*/
any &operator=(any &&rhs) noexcept
{
rhs.swap(*this);
any().swap(rhs);
return *this;
}
/**
* Assigns contents to the contained value.
* Assigns the type and value of rhs, as if by any(std::forward<ValueType>(rhs)).swap(*this).
* This overload only participates in overload resolution if std::decay_t<ValueType> is not
* the same type as any and std::is_copy_constructible_v<std::decay_t<ValueType>> is true.
*
* @param rhs object whose contained value to assign
*/
template<class ValueType>
any &operator=(ValueType &&rhs)
{
any(static_cast<ValueType &&>(rhs)).swap(*this);
return *this;
}
/**
* If not empty, destroys the contained object.
*/
void reset() noexcept { any().swap(*this); }
/**
* Swaps the content of two any objects.
*
* @param other object to swap with
*/
any &swap(any &rhs) noexcept
{
std::swap(content, rhs.content);
return *this;
}
/**
* Checks whether the object contains a value.
*
* @return true if instance contains a value, otherwise false.
*/
bool has_value() const noexcept { return content; }
/**
* Queries the contained type.
*
* The typeid of the contained value if instance is non-empty, otherwise typeid(void).
*/
const std::type_info &type() const noexcept { return content ? content->type() : typeid(void); }
private:
class placeholder {
public:
virtual ~placeholder() {}
public:
virtual const std::type_info &type() const noexcept = 0;
virtual placeholder *clone() const = 0;
};
template<typename ValueType>
class holder : public placeholder {
public:
holder(const ValueType &value) : held(value) {}
holder(ValueType &&value) : held(static_cast<ValueType &&>(value)) {}
virtual const std::type_info &type() const noexcept { return typeid(ValueType); }
virtual placeholder *clone() const { return new holder(held); }
ValueType held;
private:
holder &operator=(const holder &);
};
private:
template<typename ValueType>
friend ValueType *any_cast(any *) noexcept;
placeholder *content;
};
/**
* Overloads the std::swap algorithm for std::any. Swaps the content of two any objects by calling lhs.swap(rhs).
*
* @param lhs objects to swap
* @param rhs objects to swap
*/
inline void
swap(any &lhs, any &rhs) noexcept
{
lhs.swap(rhs);
}
/**
* Defines a type of object to be thrown by the value-returning forms of libanyboost::any_cast on failure.
*/
class bad_any_cast : public std::bad_cast {
public:
/**
* Returns the explanatory string.
*
* Pointer to a null-terminated string with explanatory information. The pointer is guaranteed to be
* valid at least until the exception object from which it is obtained is destroyed, or until a
* non-const member function on the exception object is called.
*/
virtual const char *what() const noexcept override { return "bad any_cast"; }
};
/**
* Performs type-safe access to the contained object.
*
* Throws libanyboost::bad_any_cast if the typeid of the requested
* ValueType does not match that of the contents of operand.
*
* @param operand target any object
*/
template<typename ValueType>
ValueType *
any_cast(any *operand) noexcept
{
return operand && operand->type() == typeid(ValueType)
? std::addressof(
static_cast<any::holder<typename std::remove_cv<ValueType>::type> *>(operand->content)
->held)
: 0;
}
/**
* Performs type-safe access to the contained object.
*
* Throws libanyboost::bad_any_cast if the typeid of the requested
* ValueType does not match that of the contents of operand.
*
* @param operand target any object
*/
template<typename ValueType>
inline const ValueType *
any_cast(const any *operand) noexcept
{
return any_cast<ValueType>(const_cast<any *>(operand));
}
/**
* Performs type-safe access to the contained object.
*
* Throws libanyboost::bad_any_cast if the typeid of the requested
* ValueType does not match that of the contents of operand.
*
* @param operand target any object
*/
template<typename ValueType>
ValueType
any_cast(any &operand)
{
typedef typename std::remove_reference<ValueType>::type nonref;
nonref *result = any_cast<nonref>(std::addressof(operand));
if (!result) throw bad_any_cast();
typedef typename std::conditional<std::is_reference<ValueType>::value,
ValueType,
typename std::add_lvalue_reference<ValueType>::type>::type
ref_type;
return static_cast<ref_type>(*result);
}
/**
* Performs type-safe access to the contained object.
*
* Throws libanyboost::bad_any_cast if the typeid of the requested
* ValueType does not match that of the contents of operand.
*
* @param operand target any object
*/
template<typename ValueType>
inline ValueType
any_cast(const any &operand)
{
typedef typename std::remove_reference<ValueType>::type nonref;
return any_cast<const nonref &>(const_cast<any &>(operand));
}
/**
* Performs type-safe access to the contained object.
*
* Throws libanyboost::bad_any_cast if the typeid of the requested
* ValueType does not match that of the contents of operand.
*
* @param operand target any object
*/
template<typename ValueType>
inline ValueType
any_cast(any &&operand)
{
static_assert(std::is_rvalue_reference<ValueType &&>::value
|| std::is_const<typename std::remove_reference<ValueType>::type>::value,
"any_cast shall not be used for getting nonconst references to "
"temporary objects");
return any_cast<ValueType>(operand);
}
}// namespace reflection
}// namespace meta
#endif /* META_ANY_H */

60
runtime/apply.h Normal file
View File

@ -0,0 +1,60 @@
#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

View File

@ -1,11 +1,67 @@
#pragma once
#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>
#include <string>
#include <type_traits>
#include <vector>
namespace meta {
namespace reflection {
namespace detail {
inline std::string
RemoveTypeSpace(const std::string &str, const std::string &chars = "[]()<>*&:")
{
std::string result;
// trim
{
result = str.substr(str.find_first_not_of(' '));
result = result.substr(0, result.find_last_not_of(' ') + 1);
}
// remove right space
for (size_t i = 0; i < result.size();) {
if (result[i] == ' ') {
bool left_is_chars = i > 0 && chars.find(result[i - 1]) != std::string::npos;
bool right_is_chars
= (i + 1 < str.size()) && chars.find(result[i + 1]) != std::string::npos;
if (left_is_chars || right_is_chars) {
result.erase(i, 1);
} else {
++i;
}
} else {
++i;
}
}
return result;
}
template<typename T, typename U = typename std::decay<T>::type>
std::string
PrettyNameImpl()
{
const std::string name = typeid(U).name();
std::string pretty_name = name;
int status = -4;
char *res = abi::__cxa_demangle(name.c_str(), nullptr, nullptr, &status);
if (status == 0) { pretty_name = std::string(res); }
free(res);
return RemoveTypeSpace(pretty_name);
}
}// namespace detail
template<typename T>
inline const std::string &
PrettyName()
{
static std::string pretty_name = detail::PrettyNameImpl<T>();
return pretty_name;
}
#if defined(__REFLECTION_PARSER__)
#define META(...) __attribute__((annotate(#__VA_ARGS__)))
@ -17,139 +73,119 @@ namespace meta {
#define STRUCT(struct_name, ...) struct struct_name
#endif// __REFLECTION_PARSER_
#define REFLECTION_BODY(class_name) \
#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 Constructor;
class Method;
class Field;
class Class;
class BaseType {
public:
BaseType(const std::string &name, std::shared_ptr<Class> parent) : name_(name), parent_(parent)
{}
virtual ~BaseType() = default;
std::string Name() const { return name_; }
std::shared_ptr<Class> Parent() const { return parent_; }
private:
const std::string name_;
std::shared_ptr<Class> parent_;
};
class Method : public BaseType {
public:
Method(const std::string &name, std::shared_ptr<Class> parent) : BaseType(name, parent) {}
~Method() override = default;
std::shared_ptr<Class> Parent() const { return parent_; }
template<typename ReturnT,
typename std::enable_if<!std::is_void<ReturnT>::value, ReturnT>::type * = nullptr,
typename... Params>
inline ReturnT InvokeAndCast(void *instance, Params &&...params) const
{
return ::meta::reflection::any_cast<ReturnT>(InvokeImpl(instance, {&params...}));
}
template<typename ReturnT,
typename std::enable_if<std::is_void<ReturnT>::value, int>::type * = nullptr,
typename... Params>
inline void InvokeAndCast(void *instance, Params &&...params) const
{
::meta::reflection::any_cast<ReturnT>(InvokeImpl(instance, {&params...}));
}
template<typename... Params>
inline ::meta::reflection::any Invoke(void *instance, Params &&...params) const
{
return InvokeImpl(instance, {&params...});
}
protected:
virtual ::meta::reflection::any InvokeImpl(void *instance,
const std::vector<void *> &params) const
= 0;
private:
std::shared_ptr<Class> parent_;
};
class Field : public BaseType {
public:
Field(const std::string &name, std::shared_ptr<Class> parent) : BaseType(name, parent) {}
template<typename T, typename std::enable_if<!std::is_void<T>::value, T>::type * = nullptr>
inline T GetAndCast(void *instance) const
{
return ::meta::reflection::any_cast<T>(GetImpl(instance));
}
::meta::reflection::any Get(void *instance) const { return GetImpl(instance); }
template<typename T>
inline void Set(void *instance, const T &value) const
{
SetImpl(instance, ::meta::reflection::any(value));
}
protected:
virtual ::meta::reflection::any GetImpl(void *instance) const = 0;
virtual void SetImpl(void *instance, const ::meta::reflection::any &value) const = 0;
};
class Class : public BaseType {
public:
Class(const std::string &name, std::shared_ptr<Class> base_class = nullptr)
: BaseType(name, base_class)
{}
};
#define REFLECTION_BODY() \
friend class meta::Serializer; \
friend class meta::Class; \
friend class meta::Method; \
friend class meta::Field; \
friend class meta::Constructor;
class TypeInfo {
public:
TypeInfo(const std::string &name) : name_(name) {}
virtual ~TypeInfo() = default;
std::string name() const;
virtual bool IsStatic() const = 0;
virtual bool IsConst() const = 0;
virtual bool IsWritable() const { return !IsConst(); };
private:
const std::string name_;
};
class Class;
class Constructor;
class Field;
class Method;
class Class : public TypeInfo {
public:
Class(const std::string &name) : TypeInfo(name) {}
~Class() override = default;
Constructor GetConstructor(const std::string &name) const;
Field GetField(const std::string &name) const;
Method GetMethod(const std::string &name) const;
};
/**
* class Test {
* Test();
* Test(int val);
* Test(const Test & other);
* };
**/
class Constructor : public TypeInfo {
public:
Constructor(const std::string &name, const Class &clz) : TypeInfo(name), parent_(clz) {}
~Constructor() override = default;
template<typename... Args>
void *NewInstance(Args... args) const
{
return NewInstanceImpl({&args...});
}
protected:
virtual void *NewInstanceImpl(const std::vector<void *> &args) const = 0;
const Class &parent_;
};
class Field : public TypeInfo {
public:
Field(const std::string &name, const Class &clz) : TypeInfo(name), parent_(clz) {}
~Field() override = default;
template<typename T>
void Set(void *instance, T &&value) const
{
SetImpl(instance, &value);
}
template<typename T>
const T &Get(void *instance) const
{
return *static_cast<T *>(GetImpl(instance));
}
template<typename T>
T &Get(void *instance) const
{
return *static_cast<T *>(GetImpl(instance));
}
protected:
virtual void SetImpl(void *instance, void *value) const = 0;
virtual void *GetImpl(void *instance) const = 0;
const Class &parent_;
};
class Method : public TypeInfo {
public:
Method(const std::string &name, const Class &clz) : TypeInfo(name), parent_(clz) {}
~Method() override = default;
template<typename ReturnT,
typename std::enable_if<!std::is_void<ReturnT>::value, ReturnT>::type * = nullptr>
inline ReturnT InvokeProxy(void *instance, const std::vector<void *> &args) const
{
return *static_cast<ReturnT *>(InvokeImpl(instance, args));
}
inline void InvokeProxy(void *instance, const std::vector<void *> &args) const
{
InvokeImpl(instance, args);
}
template<typename ReturnT, typename... Args>
inline ReturnT Invoke(void *instance, Args... args)
{
return InvokeProxy<ReturnT>(instance, {&args...});
}
template<typename... Args>
inline void Invoke(void *instance, Args... args)
{
InvokeProxy<void>(instance, {&args...});
}
protected:
virtual void *InvokeImpl(void *instance, const std::vector<void *> &args) const = 0;
const Class &parent_;
};
class Reflectioin {
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);
};
}// namespace reflection
}// namespace meta

View File

@ -5,6 +5,8 @@
#include "reflection.h"
namespace test {
class TypeDef {};
CLASS(Test)
{
public:
@ -17,6 +19,7 @@ public:
int GetA() const { return a_; }
int kk(int, void *);
TypeDef GetTypeDef() const { return type_def_; }
private:
struct Void {};
@ -29,6 +32,9 @@ private:
const int b_;
int a_;
META("TypeDef")
TypeDef type_def_;
};
}// namespace test

View File

@ -19,12 +19,14 @@ public:
CursorType(const CXType &handle);
std::string GetDisplayName(void) const;
bool IsConst(void) const;
// for Function type
int GetArgumentCount(void) const;
CursorType GetArgument(unsigned index) const;
CursorType GetCanonicalType(void) const;
Cursor GetDeclaration(void) const;
CXTypeKind GetKind(void) const;
bool IsConst(void) const;
CXType handle() const { return handle_; }

View File

@ -1,5 +1,6 @@
#include "parser.h"
#include "utils.h"
#include <sled/cleanup.h>
#include <sled/log/log.h>
#include <sled/strings/utils.h>
@ -38,30 +39,29 @@ Parser::Parse(const std::string &file_name, std::vector<const char *> extra_args
0,
CXTranslationUnit_None);
CXDiagnosticSet diagnostics = clang_getDiagnosticSetFromTU(translation_unit_);
sled::Cleanup<> diagnostic_cleanup([&diagnostics] { clang_disposeDiagnosticSet(diagnostics); });
unsigned num_diagnostics = clang_getNumDiagnosticsInSet(diagnostics);
for (unsigned i = 0; i < num_diagnostics; ++i) {
CXDiagnostic diagnostic = clang_getDiagnosticInSet(diagnostics, i);
sled::Cleanup<> cleanup([&diagnostic] { clang_disposeDiagnostic(diagnostic); });
auto msg = ToString(clang_formatDiagnostic(diagnostic, CXDiagnostic_DisplaySourceLocation));
std::string filename;
{
CXSourceLocation diagLoc = clang_getDiagnosticLocation(diagnostic);
// ignore error from std
if (clang_Location_isInSystemHeader(diagLoc)) { continue; };
CXFile file;
clang_getExpansionLocation(diagLoc, &file, nullptr, nullptr, nullptr);
filename = ToString(clang_getFileName(file));
}
if (sled::EndsWith(filename, "reflection.h")) {
clang_disposeDiagnostic(diagnostic);
continue;
}
// ignore error for reflection.h
if (sled::EndsWith(filename, "reflection.h")) { continue; }
clang_disposeDiagnostic(diagnostic);
if (msg.find("error: use of undeclared identifier 'std'") == std::string::npos) {
LOGE("parser", "diagnostic: {}", msg);
}
}
clang_disposeDiagnosticSet(diagnostics);
return translation_unit_ != nullptr;
}

View File

@ -3,47 +3,88 @@
#include "types/method.h"
namespace meta {
/**
* {
* class_name = "class_name",
* properties = []
* class_type = "ns1::ns2::class_name",
* fields = [
* ],
* methods = [
* {
* name = "method_name",
* properties = []
* is_const = false,
* return_type = "int",
* params = [
* {
* name = "arg_name1",
* type = "int",
* },
* {
* name = "arg_name2",
* type = "void*",
* }
* ]
* }
* ]
* }
**/
void
BaseGenerator::GenClassRenderData(Class *clz, Mustache::data &class_def)
BaseGenerator::GenClassRenderData(Class *clz, inja::json &class_def)
{
class_def.set("class_name", clz->name());
class_def.set("class_need_registry", true);
class_def["class_name"] = clz->Name();
class_def["class_namespace"] = sled::StrJoin(clz->namespaces(), "::");
class_def["properties"] = inja::json::array();
for (auto &prop : clz->properties()) { class_def["properties"].push_back(prop); }
Mustache::data class_field_defines = Mustache::data::type::list;
GenClassFieldRenderData(clz, class_field_defines);
class_def.set("class_field_defines", class_field_defines);
inja::json methods = inja::json::array();
inja::json fields = inja::json::array();
Mustache::data class_method_defines = Mustache::data::type::list;
GenClassMethodRenderData(clz, class_method_defines);
class_def.set("class_method_defines", class_method_defines);
GenClassMethodRenderData(clz, methods);
GenClassFieldRenderData(clz, fields);
class_def["class_methods"] = methods;
class_def["class_fields"] = fields;
}
void
BaseGenerator::GenClassFieldRenderData(Class *clz, Mustache::data &field_defs)
BaseGenerator::GenClassConstructorRenderData(Class *clz, inja::json &constructor_defs)
{}
void
BaseGenerator::GenClassFieldRenderData(Class *clz, inja::json &field_defs)
{
for (auto &field : clz->fields()) {
Mustache::data field_def;
field_def.set("class_field_name", field->name());
field_def.set("class_field_type", field->type_name());
field_def.set("class_field_display_name", field->cursor().GetDisplayName());
if (field->type_name().find("std::vector") != std::string::npos) {
field_def.set("class_field_is_vector", true);
} else {
field_def.set("class_field_is_vector", false);
}
inja::json field_def;
field_def["name"] = field->Name();
field_def["is_const"] = field->IsConst();
field_def["properties"] = inja::json::array();
for (auto &prop : field->properties()) { field_def["properties"].push_back(prop); }
field_def["type"] = field->cursor().GetType().GetDisplayName();
field_defs.push_back(field_def);
}
}
void
BaseGenerator::GenClassMethodRenderData(Class *clz, Mustache::data &method_defs)
BaseGenerator::GenClassMethodRenderData(Class *clz, inja::json &method_defs)
{
for (auto &method : clz->methods()) {
Mustache::data method_def;
method_def.set("class_method_name", method->name());
method_def.set("class_method_return_type", method->return_type().GetDisplayName());
method_def.set("class_method_display_name", method->cursor().GetDisplayName());
inja::json method_def;
method_def["name"] = method->Name();
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 &param : method->arguments()) {
inja::json param_def;
param_def["name"] = "";
param_def["type"] = param.GetDisplayName();
params.push_back(param_def);
}
method_def["params"] = params;
method_defs.push_back(method_def);
}
}

View File

@ -2,21 +2,20 @@
#ifndef META_GENERATORS_BASE_GENERATOR_H
#define META_GENERATORS_BASE_GENERATOR_H
#include "inja.hpp"
#include "types/class.h"
#include <mustache.hpp>
#include <string>
namespace meta {
using namespace kainjow;
namespace Mustache = kainjow::mustache;
class BaseGenerator {
public:
virtual ~BaseGenerator() = default;
virtual void Generate() = 0;
virtual void GenClassRenderData(Class *clz, Mustache::data &class_def);
virtual void GenClassFieldRenderData(Class *clz, Mustache::data &field_defs);
virtual void GenClassMethodRenderData(Class *clz, Mustache::data &method_defs);
virtual void GenClassRenderData(Class *clz, inja::json &class_def);
virtual void GenClassConstructorRenderData(Class *clz, inja::json &constructor_defs);
virtual void GenClassFieldRenderData(Class *clz, inja::json &field_defs);
virtual void GenClassMethodRenderData(Class *clz, inja::json &method_defs);
};
}// namespace meta

View File

@ -1,15 +1,132 @@
#include "generators/base_generator.h"
#include "reflection.h"
#include "registry.h"
#include "types/class.h"
#include "clang/parser.h"
#include <fstream>
#include <sled/any.h>
#include <sled/apply.h>
#include <sled/filesystem/path.h>
#include <sled/log/log.h>
#include <sled/strings/utils.h>
#include <tuple>
const char *kTag = "main";
class Generator : public meta::BaseGenerator {
public:
Generator(const std::string &template_path)
{
std::fstream in(template_path, std::ios::in);
std::stringstream ss;
ss << in.rdbuf();
template_ = ss.str();
}
~Generator() override = default;
void Generate() override
{
for (auto &clz : meta::Registry::Instance()->classes()) {
inja::json class_def;
GenClassRenderData(clz, class_def);
inja::Environment env;
env.set_trim_blocks(true);
env.set_lstrip_blocks(true);
try {
LOGV(kTag, "data={}", class_def.dump());
LOGV(kTag, "class_def={}", env.render(template_, class_def));
} catch (const std::exception &e) {
LOGE(kTag, "error: {}", e.what());
}
}
}
private:
std::string template_;
};
// 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 *> &params) 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_;
};
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;
int i = 0;
@ -34,5 +151,10 @@ main(int argc, char *argv[])
LOGI(kTag, "{}\n{}", meta::Registry::Instance()->GetQualifiedName(clz), clz->ToString());
}
Generator generator1("template/class_proxy_include.inja");
generator1.Generate();
Generator generator2("template/class_proxy_source.inja");
generator2.Generate();
return 0;
}

View File

@ -39,7 +39,7 @@ void
Registry::AddClass(Class *cls)
{
if (!cls->ShouldGenerate()) { return; }
const std::string key = sled::StrJoin(cls->namespaces(), "::") + "::" + cls->name();
const std::string key = sled::StrJoin(cls->namespaces(), "::") + "::" + cls->Name();
if (class_by_qualified_name_.find(key) == class_by_qualified_name_.end()) {
class_by_qualified_name_[key] = cls;
qualified_name_by_class_[cls] = key;

View File

@ -19,11 +19,11 @@ BaseType::BaseType(const Cursor &cursor, const std::vector<std::string> &namespa
}
}
std::string
BaseType::type_name() const
{
return cursor_.GetType().GetDisplayName();
}
// std::string
// BaseType::type_name() const
// {
// return sled::StrJoin(namespaces_, "::") + "::" + name();
// }
std::vector<std::string>
BaseType::GetProperties(const Cursor &annotation_cursor)
@ -38,7 +38,7 @@ std::string
BaseType::ToString() const
{
std::stringstream ss;
ss << name();
ss << Name();
if (!properties_.empty()) { ss << " /*" << sled::StrJoin(properties(), ",") << "*/"; }
return ss.str();
}

View File

@ -2,8 +2,28 @@
#ifndef META_TYPES_TYPE_INTERFACE_H
#define META_TYPES_TYPE_INTERFACE_H
#include "clang/cursor.h"
#include <algorithm>
namespace meta {
/**
* Class (class test)
* - is_const = false
* - name = test
* - type_name = test
* Method (int foo(int a, int b) const)
* - is_const = true
* - name = foo
* - type = int(int, int) const
* - type_name = int(int, int) const
* - return_type = int
* - arguments = [int, int]
* - argument_count = 2
* Field (const int foo)
* - is_const = true
* - name = foo
* - type const int
* - type_name = const int
**/
class BaseType {
public:
static std::vector<std::string> GetProperties(const Cursor &annotation_cursor);
@ -11,22 +31,27 @@ public:
BaseType(const Cursor &cursor, const std::vector<std::string> &namespaces);
virtual ~BaseType() = default;
virtual std::string name() const { return cursor_.GetSpelling(); }
virtual bool IsConst() const { return false; }
virtual std::string type_name() const;
virtual std::string Name() const { return cursor_.GetSpelling(); }
virtual std::string TypeName() const = 0;
virtual std::string ToString() const;
virtual bool ShouldGenerate() const { return !properties_.empty(); }
bool IsPublic() const { return clang_getCXXAccessSpecifier(cursor_.handle()) == CX_CXXPublic; }
inline bool IsPublic() const
{
return clang_getCXXAccessSpecifier(cursor_.handle()) == CX_CXXPublic;
}
bool IsPrivate() const
inline bool IsPrivate() const
{
return clang_getCXXAccessSpecifier(cursor_.handle()) == CX_CXXPrivate;
}
bool IsProtected() const
inline bool IsProtected() const
{
return clang_getCXXAccessSpecifier(cursor_.handle()) == CX_CXXProtected;
}

View File

@ -13,6 +13,8 @@ Class::Class(const Cursor &cursor, const std::vector<std::string> &namespaces)
for (auto &child : cursor.GetChildren()) {
switch (child.GetKind()) {
case CXCursor_Constructor:
constructors_.push_back(new Method(child, namespaces_, *this));
should_generate_ = should_generate_ || constructors_.back()->ShouldGenerate();
break;
case CXCursor_CXXMethod:
methods_.push_back(new Method(child, namespaces_, *this));
@ -69,4 +71,10 @@ Class::ToString() const
return ss.str();
}
std::string
Class::TypeName() const
{
return sled::StrJoin(namespaces_, "::") + "::" + Name();
}
}// namespace meta

View File

@ -17,14 +17,18 @@ public:
Class(const Cursor &cursor, const std::vector<std::string> &namespaces);
~Class() override;
std::string ToString() const override;
std::string TypeName() const override;
bool ShouldGenerate() const override { return should_generate_; }
const std::vector<Method *> &constructors() const { return constructors_; }
const std::vector<Field *> &fields() const { return fields_; }
const std::vector<Method *> &methods() const { return methods_; }
private:
std::vector<Method *> constructors_;
std::vector<Field *> fields_;
std::vector<Method *> methods_;
bool should_generate_;

View File

@ -19,7 +19,13 @@ Field::Field(const Cursor &cursor, const std::vector<std::string> &namespaces, c
std::string
Field::ToString() const
{
return type_name() + " " + BaseType::ToString();
return TypeName() + " " + BaseType::ToString();
}
std::string
Field::TypeName() const
{
return cursor().GetType().GetDisplayName();
}
}// namespace meta

View File

@ -13,6 +13,7 @@ public:
~Field() override = default;
std::string ToString() const override;
std::string TypeName() const override;
private:
const Class &parent_;

View File

@ -21,7 +21,7 @@ Method::ToString() const
{
std::stringstream ss;
// ss << type_name();
ss << return_type_.GetDisplayName() << " " << name() << "(";
ss << return_type_.GetDisplayName() << " " << Name() << "(";
for (unsigned i = 0; i < arguments_.size(); ++i) {
ss << arguments_[i].GetDisplayName();
if (i < arguments_.size() - 1) { ss << ", "; }
@ -33,6 +33,13 @@ Method::ToString() const
return ss.str();
}
std::string
Method::TypeName() const
{
// return sled::StrJoin(namespaces_, "::") + "::" + name();
return cursor().GetType().GetDisplayName();
}
bool
Method::IsConst() const
{

View File

@ -11,11 +11,15 @@ public:
~Method() override = default;
std::string ToString() const override;
std::string TypeName() const override;
bool IsConst() const;
CursorType return_type() const;
CursorType argument(unsigned index) const;
std::vector<CursorType> arguments() const;
bool IsConst() const override;
CursorType return_type() const { return return_type_; }
CursorType argument(unsigned index) const { return arguments_[index]; }
std::vector<CursorType> arguments() const { return arguments_; };
private:
const Class &parent_;

View File

@ -2,13 +2,37 @@
#ifndef META_UTILS_H
#define META_UTILS_H
#include <clang-c/Index.h>
#include <sled/strings/utils.h>
#include <string>
namespace meta {
inline std::string ToString(const CXString& str) {
inline std::string
ToString(const CXString &str)
{
std::string result = clang_getCString(str);
clang_disposeString(str);
return result;
}
}
#endif // META_UTILS_H
inline std::string
RemoveTypeSpace(const std::string &str, const std::string &chars = "[]()<>*&:")
{
std::string res = sled::Trim(str);
// remove right space
for (size_t i = 0; i < str.size();) {
if (str[i] == ' ') {
bool left_is_chars = i > 0 && chars.find(str[i - 1]) != std::string::npos;
bool right_is_chars
= (i + 1 < str.size()) && chars.find(str[i + 1]) != std::string::npos;
if (left_is_chars || right_is_chars) {
res.erase(i, 1);
} else {
++i;
}
}
}
return res;
}
}// namespace meta
#endif// META_UTILS_H

View File

@ -0,0 +1,34 @@
#pragma once
#ifndef META_GEN_{{class_name}}_PROXY_H
#define META_GEN_{{class_name}}_PROXY_H
#include "runtime/reflection.h"
namespace meta {
namespace reflection {
class {{class_name}}_Class : public ::meta::reflection::Class {
};
class {{class_name}}_Field : public ::meta::reflection::Field {
public:
{{class_name}}_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 {{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 *> &params) const override;
};
} // namespace reflection
} // namespace meta
#endif // META_GEN_{{class_name}}_PROXY_H

View File

@ -0,0 +1,78 @@
#include "{{class_name}}.gen.h"
#include <string.h>
namespace meta {
namespace reflection {
/**
* Field
**/
{{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 {
::{{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}}; }
{% endfor %}
}
void 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}}>();}
{% endif %}
{% endfor %}
}
/**
* Method
**/
{{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 *> &params) 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 method.return_type != "void" %}
return obj->{{method.name}}(
{% for param in method.params%}
*({{param.type}}*)params[{{loop.index}}]{% if not loop.is_last %}, {% endif %}
{% endfor %}
);
{% else %}
obj->{{method.name}}(
{% for param in method.params%}
*({{param.type}}*)params[{{loop.index}}]{% if not loop.last %}, {% endif %}
{% endfor %}
);
return;
{% endif %}
{% if loop.is_last %}
}
{% endif %}
{% endfor %}
}
} // namespace reflection
} // namespace meta