feat use inja generate
This commit is contained in:
parent
ab434df5fc
commit
fd8ae6c6bd
4753
3rdparty/inja/inja.hpp
vendored
Normal file
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
24765
3rdparty/inja/nlohmann/json.hpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1195
3rdparty/mustache/mustache.hpp
vendored
1195
3rdparty/mustache/mustache.hpp
vendored
File diff suppressed because it is too large
Load Diff
2
3rdparty/sled
vendored
2
3rdparty/sled
vendored
@ -1 +1 @@
|
||||
Subproject commit f31657640f5731c2f86206190fe1d59728225795
|
||||
Subproject commit fcce11249be00ca0c7f8c2e75938de4b3e5f26da
|
@ -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
329
runtime/any.h
Normal 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
60
runtime/apply.h
Normal 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
|
@ -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, {¶ms...}));
|
||||
}
|
||||
|
||||
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, {¶ms...}));
|
||||
}
|
||||
|
||||
template<typename... Params>
|
||||
inline ::meta::reflection::any Invoke(void *instance, Params &&...params) const
|
||||
{
|
||||
return InvokeImpl(instance, {¶ms...});
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ::meta::reflection::any InvokeImpl(void *instance,
|
||||
const std::vector<void *> ¶ms) 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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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_; }
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 ¶m : 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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
122
src/main.cc
122
src/main.cc
@ -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 *> ¶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_;
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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_;
|
||||
|
@ -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
|
||||
|
@ -13,6 +13,7 @@ public:
|
||||
~Field() override = default;
|
||||
|
||||
std::string ToString() const override;
|
||||
std::string TypeName() const override;
|
||||
|
||||
private:
|
||||
const Class &parent_;
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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_;
|
||||
|
30
src/utils.h
30
src/utils.h
@ -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
|
||||
|
34
template/class_proxy_include.inja
Normal file
34
template/class_proxy_include.inja
Normal 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 *> ¶ms) const override;
|
||||
};
|
||||
|
||||
} // namespace reflection
|
||||
} // namespace meta
|
||||
|
||||
#endif // META_GEN_{{class_name}}_PROXY_H
|
||||
|
78
template/class_proxy_source.inja
Normal file
78
template/class_proxy_source.inja
Normal 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 *> ¶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 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
|
||||
|
Loading…
x
Reference in New Issue
Block a user