refl support overload

This commit is contained in:
ouczbs 2024-06-21 22:20:13 +08:00
parent e4bba053cc
commit 6d4d39ee4e
8 changed files with 189 additions and 103 deletions

View File

@ -1,5 +1,7 @@
using CppAst;
using Irony;
using static System.Net.Mime.MediaTypeNames;
using static System.Runtime.InteropServices.JavaScript.JSType;
namespace refl
{
@ -7,11 +9,13 @@ namespace refl
{
public string Name { get; set; }
public string Meta { get; set; }
public string Ref { get; set; }
//public Dictionary<string, string> UserMeta = new Dictionary<string, string>();
public FieldData(string name, string meta)
{
Name = name;
Meta = meta;
Meta = "{" + meta + "}";
Ref = "";
}
}
@ -46,8 +50,10 @@ namespace refl
{
public static HashSet<string> NameSet = new HashSet<string>();
public string NameSpace { get; set; }
public List<ClassMeta> ClassList;
public List<ClassMeta> ClassList;
public List<ModuleMeta> ChildList;
public static OverTree OverData = new OverTree();
public ModuleMeta(string name_space)
{
NameSpace = name_space;
@ -71,6 +77,7 @@ namespace refl
}
}
ClassMeta cls_meta = new ClassMeta(cppClass.Name, parentName);
OverData.Clear();
foreach (var field in cppClass.Fields)
{
if (field.Attributes.Count == 0)
@ -93,17 +100,15 @@ namespace refl
foreach (var attribute in func.Attributes)
{
string key, value;
MetaToken.ParseMeta(attribute.Arguments, out key, out value);
string? next;
MetaToken.ParseAllMeta(attribute.Arguments, out key, out value, out next);
FieldData data = new FieldData(key, value);
if (!cls_meta.Fields.ContainsKey(key))
{
cls_meta.Fields.Add(key, new FieldMeta());
}
List<string> nameList = new List<string>{ "T" };
foreach (var parm in func.Parameters)
{
nameList.Add(parm.Type.FullName);
}
cls_meta.Fields[key].CtorList.Add(new FieldData(string.Join(",", nameList), value));
cls_meta.Fields[key].CtorList.Add(data);
ParseClassUserMeta(cppClass, data, next);
}
}
foreach (var func in cppClass.Functions)
@ -113,23 +118,43 @@ namespace refl
foreach (var attribute in func.Attributes)
{
string key, value;
MetaToken.ParseMeta(attribute.Arguments, out key, out value);
string? next;
MetaToken.ParseAllMeta(attribute.Arguments, out key, out value, out next);
FieldData data = new FieldData(func.Name, value);
if (!cls_meta.Fields.ContainsKey(key))
{
cls_meta.Fields.Add(key, new FieldMeta());
}
cls_meta.Fields[key].MethodList.Add(new FieldData(func.Name, value));
cls_meta.Fields[key].MethodList.Add(data);
ParseClassUserMeta(cppClass, data, next);
}
}
return cls_meta;
}
public static void ParseClassUserMeta(CppClass cppClass, FieldData data, string? next)
{
if (next == null)
return;
OverData.Init(cppClass);
string key, value;
while (next != null)
{
MetaToken.ParseAllMeta(next, out key, out value, out next);
if (key == "ref")
{
value = OverData.Find(value.Trim());
data.Ref = value;
}
//data.UserMeta.Add(key, value);
}
}
public static ModuleMeta ParseCppNamespaces(CppNamespace cpp)
{
var module = new ModuleMeta(cpp.Name);
foreach (var cppClass in cpp.Classes)
{
var cls_meta = ParseCppClass(cppClass);
if(cls_meta.Fields.Count > 0)
if (cls_meta.Fields.Count > 0)
{
module.ClassList.Add(cls_meta);
}
@ -137,7 +162,7 @@ namespace refl
foreach (var spaces in cpp.Namespaces)
{
var child = ParseCppNamespaces(spaces);
if(child.ClassList.Count > 0 || child.ChildList.Count > 0)
if (child.ClassList.Count > 0 || child.ChildList.Count > 0)
{
module.ChildList.Add(child);
}
@ -150,12 +175,12 @@ namespace refl
foreach (var cppClass in cpp.Classes)
{
var cls_meta = ParseCppClass(cppClass);
if(cls_meta.Fields.Count > 0)
if (cls_meta.Fields.Count > 0)
{
module.ClassList.Add(cls_meta);
}
}
foreach(var spaces in cpp.Namespaces)
foreach (var spaces in cpp.Namespaces)
{
var child = ParseCppNamespaces(spaces);
module.ChildList.Add(child);
@ -166,16 +191,16 @@ namespace refl
public static void ParseMetaName(ModuleMeta module)
{
ParseClassMetaName(module);
foreach(var child in module.ChildList)
foreach (var child in module.ChildList)
{
ParseMetaName(child);
}
}
public static void ParseClassMetaName(ModuleMeta module)
{
foreach(var cls in module.ClassList)
foreach (var cls in module.ClassList)
{
foreach(var field in cls.Fields)
foreach (var field in cls.Fields)
{
if (!NameSet.Contains(field.Key))
{

View File

@ -9,12 +9,14 @@ namespace refl
{
public string Name { get; set; }
public string Meta { get; set; }
public string Ref { get; set; }
public int Type { get; set; }
public FieldMetaData(string name, string meta, int type)
public FieldMetaData(FieldData data, int type)
{
Name = name;
Meta = meta;
Name = data.Name;
Meta = data.Meta;
Ref = data.Ref;
Type = type;
}
}
@ -58,15 +60,16 @@ namespace refl
data.FieldList.Clear();
foreach (var field in pair.Value.MemberList)
{
data.FieldList.Add(new FieldMetaData(field.Name, field.Meta, 1));
data.FieldList.Add(new FieldMetaData(field, 1));
}
foreach (var field in pair.Value.CtorList)
{
data.FieldList.Add(new FieldMetaData(field.Name, field.Meta, 2));
data.FieldList.Add(new FieldMetaData(field, 2));
}
foreach (var field in pair.Value.MethodList)
{
data.FieldList.Add(new FieldMetaData(field.Name, field.Meta, 3));
int type = string.IsNullOrEmpty(field.Ref) ? 3 : 4;
data.FieldList.Add(new FieldMetaData(field, type));
}
data.MemberCount = pair.Value.MemberList.Count;
data.CtorCount = pair.Value.CtorList.Count;

View File

@ -3,7 +3,6 @@ namespace refl
{
internal class MetaToken
{
/*
static bool IsMatching(char left, char right)
{
return (left == '(' && right == ')') ||
@ -15,49 +14,51 @@ namespace refl
public static int FindTokenIndex(string line)
{
Stack<char> stack = new Stack<char>();
for(int i = 0, l = line.Length;i < l; i++)
for (int i = 0, l = line.Length; i < l; i++)
{
var c = line[i];
if (c == ',' && stack.Count == 0)
{
return i;
}
if(stack.Count > 0 && IsMatching(stack.Peek(), c))
if (stack.Count > 0 && IsMatching(stack.Peek(), c))
{
stack.Pop();
}else if(c == '(' || c == '{' || c == '[' || c =='"' || c == '\'')
}
else if (c == '(' || c == '{' || c == '[' || c == '"' || c == '\'')
{
stack.Push(c);
}
}
return -1;
}
public static void ParseMeta(string line, out string key, out string value)
public static bool ParseAllMeta(string line, out string key, out string value, out string? next)
{
int index = FindTokenIndex(line);
if (index == -1)
{
key = line;
value = "{}";
ParseMeta(line, out key, out value);
next = null;
}
else
{
key = line.Substring(0, index);
value = '{' + line.Substring(index + 1) + '}';
ParseMeta(line.Substring(0, index), out key, out value);
next = line.Substring(index + 1);
}
}*/
return index != -1;
}
public static void ParseMeta(string line, out string key, out string value)
{
if (line.Contains(','))
if (line.Contains('='))
{
var res = line.Split(',', 2);
key = res[0];
value = '{' + res[1] + '}';
var res = line.Split('=', 2);
key = res[0].Trim();
value = res[1];
}
else
{
key = line;
value = "{}";
value = "";
}
}
}

74
src/refl/OverTree.cs Normal file
View File

@ -0,0 +1,74 @@
using CppAst;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace refl
{
internal class OverTree
{
public const int PrefixSize = 6;
List<int> Ctors = new List<int>();
List<int> Funcs = new List<int>();
private bool isInit = false;
public OverTree() { }
public void Init(CppClass cppClass)
{
if (isInit)
{
return;
}
isInit = true;
foreach (var types in cppClass.Typedefs)
{
string key = types.Name.Substring(0, PrefixSize);
if(key == "__Ctor")
{
Ctors.Add(int.Parse(types.Name.Substring(PrefixSize)));
}
else if(key == "__Func")
{
Funcs.Add(int.Parse(types.Name.Substring(PrefixSize)));
}
}
Ctors.Sort();
Funcs.Sort();
}
public void Clear()
{
Ctors.Clear();
Funcs.Clear();
isInit = false;
}
public string Find(string name)
{
string key = name.Substring(0, PrefixSize);
int v = int.Parse(name.Substring(PrefixSize));
if (key == "__Ctor")
{
v = FindValue(Ctors, v);
}
else
{
v = FindValue(Funcs, v);
}
return key + v;
}
private static int FindValue(List<int> sortedNumbers, int target)
{
if(sortedNumbers.Count == 0)
{
return target;
}
int index = sortedNumbers.BinarySearch(target);
if(index < 0)
{
index = ~index;
}
index = index > 0 ? index - 1 : 0;
return sortedNumbers[index];
}
}
}

6
src/refl/_install.bat Normal file
View File

@ -0,0 +1,6 @@
@echo off
set "source_dir=%CD%" REM 当前目录
set "destination_dir=F:\ouczbs\zengine\tools\refl" REM 指定目标目录
xcopy "%source_dir%\bin\Release\net8.0\win-x64\*" "%destination_dir%\" /Y
xcopy "%source_dir%\template\*" "%destination_dir%\template\" /Y
pause

View File

@ -3,28 +3,29 @@
#define __cppast(...)
#endif
#define __Meta(...) __cppast(Meta,__VA_ARGS__)
#define __Meta(...) __cppast(Meta=__VA_ARGS__)
#define UPROPERTY(...) __Meta(__VA_ARGS__)
#define UFUNCTION(...) __Meta(__VA_ARGS__)
#define __vkMeta(...) __cppast(vkMeta,__VA_ARGS__)
#define __vkMeta(...) __cppast(vkMeta=__VA_ARGS__)
#define UPROPERTY_vk(...) __vkMeta(__VA_ARGS__)
#define UFUNCTION_vk(...) __vkMeta(__VA_ARGS__)
#define __dxMeta(...) __cppast(dxMeta,__VA_ARGS__)
#define __dxMeta(...) __cppast(dxMeta=__VA_ARGS__)
#define UPROPERTY_dx(...) __dxMeta(__VA_ARGS__)
#define UFUNCTION_dx(...) __dxMeta(__VA_ARGS__)
// 辅助宏,用于实际拼接
#define CONCATENATE(arg1, arg2) CONCATENATE_IMPL(arg1, arg2)
#define CONCATENATE_IMPL(arg1, arg2) arg1##arg2
#define UNIQUE_NAME(base) CONCATENATE(base, __LINE__)
#define MY_UNIQUE_NAME(base) CONCATENATE(base, __LINE__)
#define OVERLOAD_CTOR_IMPL(Class, ...) using UNIQUE_NAME(__Ctor) = Class(*)(__VA_ARGS__);
#define OVERLOAD_FUNC_IMPL(Func, R, ...) using UNIQUE_NAME(__Func) = R(*)(__VA_ARGS__);
#define USING_CTOR_NAME MY_UNIQUE_NAME(__Ctor)
#define USING_FUNC_NAME MY_UNIQUE_NAME(__Func)
#define OVERLOAD_CTOR(Class, ...) OVERLOAD_CTOR_IMPL(Class, __VA_ARGS__);Class(__VA_ARGS__)
#define OVERLOAD_FUNC(Func, R, ...) OVERLOAD_FUNC_IMPL(Func, R, __VA_ARGS__);R Func(__VA_ARGS__)
#define USING_OVERLOAD_CTOR(Class, ...) using USING_CTOR_NAME = Class(*)(__VA_ARGS__);
#define USING_OVERLOAD_FUNC(R, ...) using USING_FUNC_NAME = R(*)(__VA_ARGS__);
#define USING_OVERLOAD_CLASS_FUNC(R, Class, ...) using USING_FUNC_NAME = R(Class::*)(__VA_ARGS__);
namespace refl_impl {
struct Meta {};

View File

@ -1,21 +1,16 @@
#include "refl/refl.h"
#include <objbase.h>
#include <objbase.h>
#include <string>
#include <vector>
using std::string;
using std::vector;
using std::string_view;
namespace engineapi {
namespace test {
struct vec1 {
UPROPERTY({})
int x;
UPROPERTY({})
int y;
};
}
namespace test {
struct Guid
{
UPROPERTY_vk({})
UPROPERTY({})
unsigned int Data1;
UPROPERTY_vk({})
UPROPERTY({})
unsigned short Data2;
UPROPERTY({})
@ -25,8 +20,10 @@ namespace engineapi {
constexpr Guid() noexcept
: Data1{ 0 }, Data2{ 0 }, Data3{ 0 }, Data4{ 0,0,0,0,0,0,0,0 }
{}
UFUNCTION({})
Guid(const string_view& str) noexcept
USING_OVERLOAD_CTOR(Guid, const string_view&)
UFUNCTION({}, ref = USING_CTOR_NAME)
Guid(const std::string_view& str) noexcept
: Guid{}
{
sscanf_s(str.data(),
@ -56,13 +53,17 @@ namespace engineapi {
{
return *reinterpret_cast<const GUID*>(this) != GUID_NULL;
}
USING_OVERLOAD_CLASS_FUNC(void, Guid, int)
UFUNCTION({}, ref = USING_FUNC_NAME)
void test(int x) {
operator string() const
{
return ToString();
}
UFUNCTION({})
string ToString() const
USING_OVERLOAD_FUNC(void, Guid, float)
UFUNCTION({}, ref = USING_FUNC_NAME)
void test(float x) {
}
operator std::string() const
{
char guid_cstr[39];
snprintf(guid_cstr, sizeof(guid_cstr),
@ -70,45 +71,16 @@ namespace engineapi {
Data1, Data2, Data3,
Data4[0], Data4[1], Data4[2], Data4[3],
Data4[4], Data4[5], Data4[6], Data4[7]);
return string{ guid_cstr };
return std::string{ guid_cstr };
}
UFUNCTION({})
static Guid Make()
{
Guid guid;
const auto res = CoCreateGuid((GUID*)&guid);
return guid;
}
};
}
namespace work {
#include <iostream>
#include <string_view>
struct Guid2 {
};
struct Guid {
using __Ctor_1 = Guid (*)(const std::string_view, Guid2);
Guid(const std::string_view& str, Guid2) {
// Construct Guid from string_view (implementation to be added)
std::cout << "Guid constructed with: " << str << std::endl;
}
};
}
namespace meta {
template<typename T, typename... Args>
static T Ctor(Args... args) {
T obj(args...); // Construct object of type T (in this case, Guid)
return obj
}
template<typename T, typename... Args>
static T(*)(Args...) CtorField() {
return &Ctor<T, Args...>;
}
void create_guid() {
using work::Guid;
Guid::__Ctor_1* c1 = CtorField<Guid::__Ctor_1>();
//...其他逻辑
}
}
#include "guid_gen.inl"

View File

@ -6,9 +6,11 @@
{{ Indent }} {%- if field.Type == 1 %}
{{ Indent }} refl::StaticMemberField(&T::{{field.Name}}, FName("{{field.Name}}"), {{field.Meta}}),
{{ Indent }} {%- elsif field.Type == 2 %}
{{ Indent }} refl::StaticCtorField<{{field.Name}}>({{field.Meta}}),
{{ Indent }} {%- else %}
{{ Indent }} refl::StaticCtorField<T::{{field.Ref}}>({{field.Meta}}),
{{ Indent }} {%- elsif field.Type == 3 %}
{{ Indent }} refl::StaticMethodField(&T::{{field.Name}}, FName("{{field.Name}}"), {{field.Meta}}),
{{ Indent }} {%- else %}
{{ Indent }} refl::StaticMethodField((T::{{field.Ref}})&T::{{field.Name}}, FName("{{field.Name}}"), {{field.Meta}}),
{{ Indent }} {%- endif %}
{{ Indent }} {%- endfor %}
{{ Indent }} };
@ -40,9 +42,11 @@
{{ Indent }} {%- if field.Type == 1 %}
{{ Indent }} MemberField(&T::{{field.Name}}, FName("{{field.Name}}"), memory, {{field.Meta}}),
{{ Indent }} {%- elsif field.Type == 2 %}
{{ Indent }} CtorField<{{field.Name}}>(memory, {{field.Meta}}),
{{ Indent }} {%- else %}
{{ Indent }} CtorField<T::{{field.Ref}}>(memory, {{field.Meta}}),
{{ Indent }} {%- elsif field.Type == 3 %}
{{ Indent }} MethodField(&T::{{field.Name}}, FName("{{field.Name}}"), memory, {{field.Meta}}),
{{ Indent }} {%- else %}
{{ Indent }} MethodField((T::{{field.Ref}})&T::{{field.Name}}, FName("{{field.Name}}"), memory, {{field.Meta}}),
{{ Indent }} {%- endif %}
{{ Indent }} {%- endfor %}
{{ Indent }} };