feat support reflect properties
This commit is contained in:
parent
0e1b34934d
commit
35ad59ab7a
@ -33,7 +33,6 @@ BraceWrapping:
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: true
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
|
2
3rdparty/sled
vendored
2
3rdparty/sled
vendored
@ -1 +1 @@
|
||||
Subproject commit 4b68474fe58fb3af754f93916438bc8d2ba6aac1
|
||||
Subproject commit d048a2676c4194e19934e0263aeb54928bbd68a6
|
@ -12,6 +12,11 @@ add_executable(meta
|
||||
src/clang/cursor.cc
|
||||
src/clang/cursor_type.cc
|
||||
src/clang/parser.cc
|
||||
src/types/base_type.cc
|
||||
src/types/class.cc
|
||||
src/types/field.cc
|
||||
src/types/method.cc
|
||||
src/registry.cc
|
||||
)
|
||||
|
||||
### add clang
|
||||
|
@ -1,11 +0,0 @@
|
||||
#include "reflection.h"
|
||||
|
||||
namespace meta {
|
||||
std::atomic<int> next_type_id{0};
|
||||
|
||||
void
|
||||
NoOp(void *)
|
||||
{}
|
||||
|
||||
Object::Object() : id_(GetTypeId<void>()), data_(nullptr), deleter_(NoOp) {}
|
||||
}// namespace meta
|
@ -1,60 +1,155 @@
|
||||
#pragma once
|
||||
#ifndef META_RUNTIME_REFLECTION_H
|
||||
#define META_RUNTIME_REFLECTION_H
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <sled/any.h>
|
||||
#include <string>
|
||||
#include <typeindex>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
namespace meta {
|
||||
#define __REFLECTION_PARSER_
|
||||
#if defined(__REFLECTION_PARSER_)
|
||||
#define CLASS(class_name, ...) \
|
||||
class __attribute__((annotate(#__VA_ARGS__))) class_name
|
||||
#define STRUCT(struct_name, ...) \
|
||||
struct __attribute__((annotate(#__VA_ARGS__))) struct_name
|
||||
|
||||
#if defined(__REFLECTION_PARSER__)
|
||||
#define META(...) __attribute__((annotate(#__VA_ARGS__)))
|
||||
#define CLASS(class_name, ...) class __attribute__((annotate(#__VA_ARGS__))) class_name
|
||||
#define STRUCT(struct_name, ...) struct __attribute__((annotate(#__VA_ARGS__))) struct_name
|
||||
#else
|
||||
#define META(...)
|
||||
#define CLASS(class_name, ...) class class_name
|
||||
#define STRUCT(struct_name, ...) struct struct_name
|
||||
#endif// __REFLECTION_PARSER_
|
||||
|
||||
#define REFLECTION_BODY(class_name)
|
||||
#define REFLECTION_BODY(class_name) \
|
||||
friend class meta::Serializer; \
|
||||
friend class meta::Class; \
|
||||
friend class meta::Method; \
|
||||
friend class meta::Field; \
|
||||
friend class meta::Constructor;
|
||||
|
||||
#define REFLECT_TYPE(class_name)
|
||||
|
||||
class TypeInterface {
|
||||
class TypeInfo {
|
||||
public:
|
||||
virtual std::string name() const = 0;
|
||||
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 Method : public TypeInterface {
|
||||
class Class : public TypeInfo {
|
||||
public:
|
||||
virtual std::string name() = 0;
|
||||
Class(const std::string &name) : TypeInfo(name) {}
|
||||
|
||||
template<typename ReturnT, typename... Args>
|
||||
ReturnT Invoke(void *instance, Args... args) const
|
||||
{
|
||||
std::vector<sled::any> arguments = {args...};
|
||||
return sled::any_cast<ReturnT>(
|
||||
std::forward<sled::any>(Invoke(instance, arguments)));
|
||||
}
|
||||
~Class() override = default;
|
||||
Constructor GetConstructor(const std::string &name) const;
|
||||
Field GetField(const std::string &name) const;
|
||||
Method GetMethod(const std::string &name) const;
|
||||
};
|
||||
|
||||
sled::any Invoke(void *instance, std::vector<sled::any> &args) 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 InvokeImpl(instance, args);
|
||||
return NewInstanceImpl({&args...});
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual sled::any InvokeImpl(void *instance,
|
||||
std::vector<sled::any> &args) const = 0;
|
||||
virtual void *NewInstanceImpl(const std::vector<void *> &args) const = 0;
|
||||
const Class &parent_;
|
||||
};
|
||||
|
||||
class Field;
|
||||
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();
|
||||
};
|
||||
|
||||
}// namespace meta
|
||||
|
||||
|
33
runtime/test.h
Normal file
33
runtime/test.h
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#ifndef META_RUNTIME_TEST_H
|
||||
#define META_RUNTIME_TEST_H
|
||||
|
||||
#include "reflection.h"
|
||||
|
||||
namespace test {
|
||||
CLASS(Test)
|
||||
{
|
||||
public:
|
||||
META("Constructor")
|
||||
Test() : a_(0) {}
|
||||
|
||||
Test(int a) : a_(a) {}
|
||||
|
||||
META("Test")
|
||||
int GetA() const { return a_; }
|
||||
|
||||
private:
|
||||
struct Void {};
|
||||
|
||||
STRUCT(VoidMeta, "VoidMeta")
|
||||
{
|
||||
META("Enable")
|
||||
int a;
|
||||
};
|
||||
|
||||
int a_;
|
||||
};
|
||||
|
||||
}// namespace test
|
||||
|
||||
#endif// META_RUNTIME_TEST_H
|
@ -10,6 +10,12 @@ Cursor::GetKind(void)
|
||||
return handle_.kind;
|
||||
}
|
||||
|
||||
CXVisibilityKind
|
||||
Cursor::GetVisibility(void)
|
||||
{
|
||||
return clang_getCursorVisibility(handle_);
|
||||
}
|
||||
|
||||
std::string
|
||||
Cursor::GetSpelling(void) const
|
||||
{
|
||||
|
@ -14,6 +14,7 @@ public:
|
||||
Cursor(const CXCursor &handle);
|
||||
|
||||
CXCursorKind GetKind(void);
|
||||
CXVisibilityKind GetVisibility(void);
|
||||
std::string GetSpelling(void) const;
|
||||
std::string GetDisplayName(void) const;
|
||||
std::string GetSourceFile(void) const;
|
||||
@ -22,6 +23,8 @@ public:
|
||||
List GetChildren(void) const;
|
||||
void VisitChildren(Visitor visitor, void *data) const;
|
||||
|
||||
CXCursor handle() const { return handle_; }
|
||||
|
||||
private:
|
||||
CXCursor handle_;
|
||||
};
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "parser.h"
|
||||
#include "utils.h"
|
||||
#include <sled/log/log.h>
|
||||
#include <sled/strings/utils.h>
|
||||
|
||||
namespace meta {
|
||||
Parser::Parser() : index_(nullptr), translation_unit_(nullptr) {}
|
||||
@ -13,10 +15,8 @@ Parser::~Parser()
|
||||
}
|
||||
|
||||
bool
|
||||
Parser::Parse(const std::string &file_name)
|
||||
Parser::Parse(const std::string &file_name, std::vector<const char *> extra_args)
|
||||
{
|
||||
const char *args[] = {"-std=c++11"};
|
||||
|
||||
if (translation_unit_) {
|
||||
clang_disposeTranslationUnit(translation_unit_);
|
||||
translation_unit_ = nullptr;
|
||||
@ -27,14 +27,42 @@ Parser::Parse(const std::string &file_name)
|
||||
index_ = nullptr;
|
||||
}
|
||||
|
||||
extra_args.insert(extra_args.end(), kDefaultArguments.begin(), kDefaultArguments.end());
|
||||
|
||||
index_ = clang_createIndex(0, 0);
|
||||
translation_unit_ = clang_parseTranslationUnit(index_,
|
||||
file_name.c_str(),
|
||||
kDefaultArguments.data(),
|
||||
kDefaultArguments.size(),
|
||||
extra_args.data(),
|
||||
extra_args.size(),
|
||||
nullptr,
|
||||
0,
|
||||
CXTranslationUnit_None);
|
||||
CXDiagnosticSet diagnostics = clang_getDiagnosticSetFromTU(translation_unit_);
|
||||
unsigned num_diagnostics = clang_getNumDiagnosticsInSet(diagnostics);
|
||||
for (unsigned i = 0; i < num_diagnostics; ++i) {
|
||||
CXDiagnostic diagnostic = clang_getDiagnosticInSet(diagnostics, i);
|
||||
auto msg = ToString(clang_formatDiagnostic(diagnostic, CXDiagnostic_DisplaySourceLocation));
|
||||
std::string filename;
|
||||
{
|
||||
CXSourceLocation diagLoc = clang_getDiagnosticLocation(diagnostic);
|
||||
CXFile file;
|
||||
clang_getExpansionLocation(diagLoc, &file, nullptr, nullptr, nullptr);
|
||||
filename = ToString(clang_getFileName(file));
|
||||
}
|
||||
|
||||
if (sled::EndsWith(filename, "reflection.h")) {
|
||||
clang_disposeDiagnostic(diagnostic);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -44,5 +72,4 @@ Parser::GetCursor(void) const
|
||||
ASSERT(translation_unit_, "translation_unit_ is nullptr");
|
||||
return clang_getTranslationUnitCursor(translation_unit_);
|
||||
};
|
||||
|
||||
}// namespace meta
|
||||
|
@ -12,25 +12,33 @@ public:
|
||||
Parser();
|
||||
~Parser();
|
||||
|
||||
bool Parse(const std::string &file_name);
|
||||
bool Parse(const std::string &file_name, std::vector<const char *> extra_args = {});
|
||||
Cursor GetCursor(void) const;
|
||||
|
||||
void AppendFileUniqueIDForIgnoreError(const CXFileUniqueID &id)
|
||||
{
|
||||
file_unique_ids_.push_back(id);
|
||||
}
|
||||
|
||||
private:
|
||||
CXIndex index_;
|
||||
CXTranslationUnit translation_unit_;
|
||||
|
||||
private:
|
||||
std::vector<const char *> kDefaultArguments = {{"-x",
|
||||
"c++",
|
||||
"-std=c++11",
|
||||
"-D__REFLECTION_PARSER__",
|
||||
"-DNDEBUG",
|
||||
"-D__clang__",
|
||||
"-w",
|
||||
"-MG",
|
||||
"-M",
|
||||
"-ferror-limit=0",
|
||||
"-oclangLog.txt"}};
|
||||
std::vector<const char *> kDefaultArguments = {{
|
||||
"-x",
|
||||
"c++",
|
||||
"-std=c++11",
|
||||
"-D__REFLECTION_PARSER__",
|
||||
"-DNDEBUG",
|
||||
"-D__clang__",
|
||||
"-w",
|
||||
"-MG",
|
||||
"-M",
|
||||
"-ferror-limit=0",
|
||||
"-oclangLog.txt",
|
||||
}};
|
||||
std::vector<CXFileUniqueID> file_unique_ids_;
|
||||
};
|
||||
}// namespace meta
|
||||
|
||||
|
@ -1,15 +0,0 @@
|
||||
#pragma once
|
||||
#ifndef META_LANGUAGE_TYPES_FIELD_H
|
||||
#define META_LANGUAGE_TYPES_FIELD_H
|
||||
#include "type.h"
|
||||
|
||||
namespace meta {
|
||||
class Field : public TypeInfo {
|
||||
public:
|
||||
virtual bool IsReadable() const;
|
||||
virtual bool IsWritable() const;
|
||||
virtual void *GetValue(void *instance) const;
|
||||
virtual void SetValue(void *instance, void *value);
|
||||
};
|
||||
}// namespace meta
|
||||
#endif// META_LANGUAGE_TYPES_FIELD_H
|
@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
#ifndef META_LANGUAGE_TYPES_TYPE_H
|
||||
#define META_LANGUAGE_TYPES_TYPE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
class TypeInfo {
|
||||
public:
|
||||
virtual ~TypeInfo() = default;
|
||||
virtual std::string name() const = 0;
|
||||
virtual std::string qualified_name() const = 0;
|
||||
};
|
||||
|
||||
#endif// META_LANGUAGE_TYPES_TYPE_H
|
34
src/main.cc
34
src/main.cc
@ -1,28 +1,38 @@
|
||||
#include "registry.h"
|
||||
#include "types/class.h"
|
||||
#include "types/field.h"
|
||||
#include "clang/parser.h"
|
||||
#include <sled/filesystem/path.h>
|
||||
#include <sled/log/log.h>
|
||||
#include <sled/strings/utils.h>
|
||||
|
||||
const char *kTag = "main";
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
LOGI(kTag, "");
|
||||
LOGI(kTag, "cwd={}", sled::Path::Current().ToString());
|
||||
meta::Parser parser;
|
||||
int i = 0;
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strncmp("--", argv[i], 2) == 0) {
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
parser.Parse("/tmp/main.cc");
|
||||
// if not find --, then start from 1
|
||||
if (i == argc) { i = 1; }
|
||||
|
||||
std::vector<const char *> extra_args(argv + i, argv + argc);
|
||||
parser.Parse("runtime/test.h", extra_args);
|
||||
|
||||
meta::Cursor cursor = parser.GetCursor();
|
||||
for (auto &child : cursor.GetChildren()) {
|
||||
auto kind = child.GetKind();
|
||||
std::vector<std::string> cur_namespaces;
|
||||
meta::Registry::Visit(cursor, cur_namespaces);
|
||||
|
||||
if (child.IsDefinition() && (kind == CXCursor_ClassDecl || kind == CXCursor_StructDecl)) {
|
||||
LOGV(kTag,
|
||||
"class={}, file={}, spelling={}",
|
||||
child.GetDisplayName(),
|
||||
child.GetSourceFile(),
|
||||
child.GetSpelling());
|
||||
} else if (kind == CXCursor_Namespace) {
|
||||
}
|
||||
for (auto &clz : meta::Registry::Instance()->classes()) {
|
||||
LOGI(kTag, "{}\n{}", meta::Registry::Instance()->GetQualifiedName(clz), clz->ToString());
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
#ifndef META_CLANG_META_INFO_H
|
||||
#define META_CLANG_META_INFO_H
|
||||
#include "clang/cursor.h"
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace meta {
|
||||
class MetaInfo {
|
||||
public:
|
||||
MetaInfo(const Cursor &cursor);
|
||||
std::string GetProperty(const std::string &key) const;
|
||||
bool GetFlag(const std::string &key) const;
|
||||
|
||||
private:
|
||||
using Property = std::pair<std::string, std::string>;
|
||||
std::unordered_map<std::string, Property> properties_;
|
||||
|
||||
std::vector<Property> ExtractProperties(const Cursor &cursor) const;
|
||||
};
|
||||
}// namespace meta
|
||||
|
||||
#endif// META_CLANG_META_INFO_H
|
@ -1,18 +0,0 @@
|
||||
#pragma once
|
||||
#ifndef META_CLANG_PARSER_PARSER_H
|
||||
#define META_CLANG_PARSER_PARSER_H
|
||||
#include <clang-c/Index.h>
|
||||
#include <string>
|
||||
|
||||
namespace meta {
|
||||
class MetaParser {
|
||||
public:
|
||||
MetaParser(const std::string &file_name);
|
||||
~MetaParser();
|
||||
|
||||
private:
|
||||
CXIndex index_;
|
||||
CXTranslationUnit translation_unit_;
|
||||
};
|
||||
}// namespace meta
|
||||
#endif// META_CLANG_PARSER_PARSER_H
|
57
src/registry.cc
Normal file
57
src/registry.cc
Normal file
@ -0,0 +1,57 @@
|
||||
#include "registry.h"
|
||||
#include <sled/strings/utils.h>
|
||||
|
||||
namespace meta {
|
||||
void
|
||||
Registry::Visit(const meta::Cursor &cursor, std::vector<std::string> &cur_namespaces)
|
||||
{
|
||||
for (auto &child : cursor.GetChildren()) {
|
||||
auto kind = child.GetKind();
|
||||
|
||||
if (child.IsDefinition() && (kind == CXCursor_ClassDecl || kind == CXCursor_StructDecl)) {
|
||||
auto clz = new meta::Class(child, cur_namespaces);
|
||||
meta::Registry::Instance()->AddClass(clz);
|
||||
} else if (kind == CXCursor_EnumDecl) {
|
||||
} else if (kind == CXCursor_Namespace) {
|
||||
std::string ns = child.GetDisplayName();
|
||||
if (!ns.empty()) {
|
||||
cur_namespaces.push_back(ns);
|
||||
Visit(child, cur_namespaces);
|
||||
cur_namespaces.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Registry *
|
||||
Registry::Instance()
|
||||
{
|
||||
static Registry registry;
|
||||
return ®istry;
|
||||
}
|
||||
|
||||
Registry::~Registry()
|
||||
{
|
||||
for (auto &cls : classes_) { delete cls; }
|
||||
}
|
||||
|
||||
void
|
||||
Registry::AddClass(Class *cls)
|
||||
{
|
||||
if (!cls->ShouldGenerate()) { return; }
|
||||
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;
|
||||
classes_.push_back(cls);
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
Registry::GetQualifiedName(Class *clz) const
|
||||
{
|
||||
auto it = qualified_name_by_class_.find(clz);
|
||||
if (it != qualified_name_by_class_.end()) { return it->second; }
|
||||
return "";
|
||||
}
|
||||
}// namespace meta
|
29
src/registry.h
Normal file
29
src/registry.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#ifndef META_REGISTRY_H
|
||||
#define META_REGISTRY_H
|
||||
#include "types/class.h"
|
||||
#include "types/field.h"
|
||||
#include "types/method.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace meta {
|
||||
class Registry {
|
||||
public:
|
||||
static Registry *Instance();
|
||||
static void Visit(const Cursor &cursor, std::vector<std::string> &namespaces);
|
||||
|
||||
~Registry();
|
||||
void AddClass(Class *clz);
|
||||
std::string GetQualifiedName(Class *clz) const;
|
||||
|
||||
std::vector<Class *> classes() const { return classes_; }
|
||||
|
||||
private:
|
||||
Registry() = default;
|
||||
// <namespace, Class>
|
||||
std::unordered_map<std::string, Class *> class_by_qualified_name_;
|
||||
std::unordered_map<Class *, std::string> qualified_name_by_class_;
|
||||
std::vector<Class *> classes_;
|
||||
};
|
||||
}// namespace meta
|
||||
#endif// META_REGISTRY_H
|
40
src/types/base_type.cc
Normal file
40
src/types/base_type.cc
Normal file
@ -0,0 +1,40 @@
|
||||
|
||||
#include "base_type.h"
|
||||
#include <sled/strings/utils.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace meta {
|
||||
BaseType::BaseType(const Cursor &cursor, const std::vector<std::string> &namespaces)
|
||||
: cursor_(cursor),
|
||||
namespaces_(namespaces)
|
||||
{
|
||||
for (auto &child : cursor.GetChildren()) {
|
||||
switch (child.GetKind()) {
|
||||
case CXCursor_AnnotateAttr:
|
||||
properties_ = GetProperties(child);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
BaseType::GetProperties(const Cursor &annotation_cursor)
|
||||
{
|
||||
auto annotation = annotation_cursor.GetSpelling();
|
||||
auto properties = sled::StrSplit(annotation, ",");
|
||||
for (auto &property : properties) { property = sled::Trim(property, " \t\n\r\""); }
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::string
|
||||
BaseType::ToString() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << name();
|
||||
if (!properties_.empty()) { ss << " [" << sled::StrJoin(properties(), ",") << "]"; }
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
}// namespace meta
|
39
src/types/base_type.h
Normal file
39
src/types/base_type.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
#ifndef META_TYPES_TYPE_INTERFACE_H
|
||||
#define META_TYPES_TYPE_INTERFACE_H
|
||||
#include "clang/cursor.h"
|
||||
|
||||
namespace meta {
|
||||
class BaseType {
|
||||
public:
|
||||
static std::vector<std::string> GetProperties(const Cursor &annotation_cursor);
|
||||
|
||||
BaseType(const Cursor &cursor, const std::vector<std::string> &namespaces);
|
||||
virtual ~BaseType() = default;
|
||||
|
||||
virtual std::string name() const { return cursor_.GetSpelling(); }
|
||||
|
||||
virtual std::string ToString() const;
|
||||
|
||||
virtual bool ShouldGenerate() const { return !properties_.empty(); }
|
||||
|
||||
bool HasProperty(const std::string &property) const
|
||||
{
|
||||
return std::find(properties_.begin(), properties_.end(), property) != properties_.end();
|
||||
};
|
||||
|
||||
const Cursor &cursor() const { return cursor_; }
|
||||
|
||||
std::vector<std::string> namespaces() const { return namespaces_; }
|
||||
|
||||
std::vector<std::string> properties() const { return properties_; }
|
||||
|
||||
protected:
|
||||
const Cursor cursor_;
|
||||
|
||||
const std::vector<std::string> namespaces_;
|
||||
std::vector<std::string> properties_;
|
||||
};// namespace meta
|
||||
}// namespace meta
|
||||
|
||||
#endif// META_TYPES_TYPE_INTERFACE_H
|
56
src/types/class.cc
Normal file
56
src/types/class.cc
Normal file
@ -0,0 +1,56 @@
|
||||
#include "class.h"
|
||||
#include "field.h"
|
||||
#include "method.h"
|
||||
#include "registry.h"
|
||||
#include <sled/log/log.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace meta {
|
||||
Class::Class(const Cursor &cursor, const std::vector<std::string> &namespaces)
|
||||
: BaseType(cursor, namespaces),
|
||||
should_generate_(BaseType::ShouldGenerate())
|
||||
{
|
||||
for (auto &child : cursor.GetChildren()) {
|
||||
switch (child.GetKind()) {
|
||||
case CXCursor_Constructor:
|
||||
break;
|
||||
case CXCursor_CXXMethod:
|
||||
methods_.push_back(new Method(child, namespaces_, *this));
|
||||
should_generate_ = should_generate_ || methods_.back()->ShouldGenerate();
|
||||
break;
|
||||
case CXCursor_FieldDecl:
|
||||
fields_.push_back(new Field(child, namespaces_, *this));
|
||||
should_generate_ = should_generate_ || fields_.back()->ShouldGenerate();
|
||||
break;
|
||||
case CXCursor_ClassDecl:
|
||||
case CXCursor_StructDecl: {
|
||||
auto cur_namespaces = namespaces_;
|
||||
cur_namespaces.push_back(cursor.GetSpelling());
|
||||
auto clz = new Class(child, cur_namespaces);
|
||||
Registry::Instance()->AddClass(clz);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Class::~Class()
|
||||
{
|
||||
for (auto &field : fields_) { delete field; }
|
||||
}
|
||||
|
||||
std::string
|
||||
Class::ToString() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "class " << BaseType::ToString() << " {\n";
|
||||
for (auto &field : fields_) { ss << " " << field->ToString() << ";\n"; }
|
||||
ss << "\n";
|
||||
for (auto &method : methods_) { ss << " " << method->ToString() << ";\n"; }
|
||||
ss << "};\n";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
}// namespace meta
|
35
src/types/class.h
Normal file
35
src/types/class.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#ifndef META_TYPES_CLASS_H
|
||||
#define META_TYPES_CLASS_H
|
||||
#include "base_type.h"
|
||||
#include "clang/cursor.h"
|
||||
#include <sled/strings/utils.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace meta {
|
||||
class Field;
|
||||
class Method;
|
||||
|
||||
class Class : public BaseType {
|
||||
public:
|
||||
constexpr static const char *kTag = "class";
|
||||
Class(const Cursor &cursor, const std::vector<std::string> &namespaces);
|
||||
~Class() override;
|
||||
std::string ToString() const override;
|
||||
|
||||
bool ShouldGenerate() const override { return should_generate_; }
|
||||
|
||||
const std::vector<Field *> &fields() const { return fields_; }
|
||||
|
||||
const std::vector<Method *> &methods() const { return methods_; }
|
||||
|
||||
private:
|
||||
std::vector<Field *> fields_;
|
||||
std::vector<Method *> methods_;
|
||||
bool should_generate_;
|
||||
};
|
||||
|
||||
}// namespace meta
|
||||
|
||||
#endif// META_TYPES_CLASS_H
|
25
src/types/field.cc
Normal file
25
src/types/field.cc
Normal file
@ -0,0 +1,25 @@
|
||||
#include "field.h"
|
||||
#include <sled/log/log.h>
|
||||
|
||||
namespace meta {
|
||||
Field::Field(const Cursor &cursor, const std::vector<std::string> &namespaces, const Class &parent)
|
||||
: BaseType(cursor, namespaces),
|
||||
parent_(parent)
|
||||
{
|
||||
for (auto &child : cursor.GetChildren()) {
|
||||
switch (child.GetKind()) {
|
||||
case CXCursor_AnnotateAttr:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
Field::ToString() const
|
||||
{
|
||||
return BaseType::ToString();
|
||||
}
|
||||
|
||||
}// namespace meta
|
21
src/types/field.h
Normal file
21
src/types/field.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
#ifndef META_TYPES_FIELD_H
|
||||
#define META_TYPES_FIELD_H
|
||||
#include "class.h"
|
||||
#include "clang/cursor.h"
|
||||
|
||||
namespace meta {
|
||||
class Field : public BaseType {
|
||||
public:
|
||||
constexpr static const char *kTag = "field";
|
||||
Field(const Cursor &cursor, const std::vector<std::string> &namespaces, const Class &parent);
|
||||
|
||||
~Field() override = default;
|
||||
|
||||
std::string ToString() const override;
|
||||
|
||||
private:
|
||||
const Class &parent_;
|
||||
};
|
||||
}// namespace meta
|
||||
#endif// META_TYPES_FIELD_H
|
17
src/types/method.cc
Normal file
17
src/types/method.cc
Normal file
@ -0,0 +1,17 @@
|
||||
#include "method.h"
|
||||
|
||||
namespace meta {
|
||||
Method::Method(const Cursor &cursor,
|
||||
const std::vector<std::string> &namespaces,
|
||||
const Class &parent)
|
||||
: BaseType(cursor, namespaces),
|
||||
parent_(parent)
|
||||
{}
|
||||
|
||||
std::string
|
||||
Method::ToString() const
|
||||
{
|
||||
return BaseType::ToString();
|
||||
}
|
||||
|
||||
}// namespace meta
|
19
src/types/method.h
Normal file
19
src/types/method.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
#ifndef META_TYPES_METHOD_H
|
||||
#define META_TYPES_METHOD_H
|
||||
#include "class.h"
|
||||
|
||||
namespace meta {
|
||||
class Method : public BaseType {
|
||||
public:
|
||||
constexpr static const char *kTag = "method";
|
||||
Method(const Cursor &cursor, const std::vector<std::string> &namespaces, const Class &parent);
|
||||
~Method() override = default;
|
||||
|
||||
std::string ToString() const override;
|
||||
|
||||
private:
|
||||
const Class &parent_;
|
||||
};
|
||||
}// namespace meta
|
||||
#endif// META_TYPES_METHOD_H
|
Loading…
x
Reference in New Issue
Block a user