From 35fcd147d85dadccc27b93962ac28656dd63f744 Mon Sep 17 00:00:00 2001 From: ouczbs Date: Sun, 21 Apr 2024 21:44:53 +0800 Subject: [PATCH] fluid --- src/refl/BuildOption.cs | 23 +++-- src/refl/ClassMeta.cs | 21 +++-- src/refl/ClassMetaGen.cs | 118 ++++++++++++++++++++---- src/refl/MetaToken.cs | 7 +- src/refl/Program.cs | 12 ++- src/refl/Properties/launchSettings.json | 3 +- src/refl/cpp/vertex.h | 3 +- src/refl/refl.csproj | 2 + src/refl/template/refl.cpp | 1 - src/refl/template/refl.liquid | 48 ++++++++++ src/refl/template/test | 52 +++++++++++ 11 files changed, 243 insertions(+), 47 deletions(-) create mode 100644 src/refl/template/refl.liquid create mode 100644 src/refl/template/test diff --git a/src/refl/BuildOption.cs b/src/refl/BuildOption.cs index dc029e8..841d7e5 100644 --- a/src/refl/BuildOption.cs +++ b/src/refl/BuildOption.cs @@ -6,25 +6,22 @@ namespace refl internal class CmdBuildOption { [Value(0, MetaName = "", Required = true, Min = 2, HelpText = "Input file(s) for parsing.")] - public IEnumerable InputFiles { get; set; } + public IEnumerable? InputFiles { get; set; } [Option('o', "output", Required = false, HelpText = "Output file for generated code.")] - public string OutputFile { get; set; } + public string OutputFile { get; set; } = ""; [Option('t', "type", Required = false, HelpText = "Type of code to generate.")] - public string CodeType { get; set; } + public string CodeType { get; set; } = ""; [Option('l', "link", Required = false, HelpText = "link to the include dir")] - public string Link { get; set; } + public string Link { get; set; } = ""; [Option('d', "define", Required = false, HelpText = "define a macro on the command line")] - public string Define { get; set; } - - [Option('n', "namespace", Required = false, HelpText = "Namespace for generated code.")] - public string Namespace { get; set; } + public string Define { get; set; } = ""; [Option('h', "help", HelpText = "Display this help message.")] - public bool Help { get; set; } + public bool Help { get; set; } = false; static CppParserOptions MakeParserOptions(CmdBuildOption opt) { @@ -54,13 +51,19 @@ namespace refl } public static int CMD_CheckBuildOption(CmdBuildOption opt) { + if(opt.InputFiles == null) + { + return -1; + } var parse_opt = MakeParserOptions(opt); var compilation = CppAst.CppParser.ParseFiles(opt.InputFiles.Skip(1).ToList(), parse_opt); // Print diagnostic messages foreach (var message in compilation.Diagnostics.Messages) if(message.Type.Equals(CppLogMessageType.Error)) Console.WriteLine(message); - ModuleMeta.ParseCompileInfo(compilation); + var module = ModuleMeta.ParseCompileInfo(compilation); + ClassMetaGen.GenNameMeta(); + ClassMetaGen.GenCppMeta(module); return 0; } } diff --git a/src/refl/ClassMeta.cs b/src/refl/ClassMeta.cs index 8ddf76a..511c937 100644 --- a/src/refl/ClassMeta.cs +++ b/src/refl/ClassMeta.cs @@ -1,9 +1,4 @@ using CppAst; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace refl { @@ -33,13 +28,15 @@ namespace refl internal class ClassMeta { public string Name { get; set; } + public string ParentName { get; set; } public string Path { get; set; } public Dictionary Fields { get; set; } - public ClassMeta(string name) + public ClassMeta(string name, string parentName) { Name = name; + ParentName = parentName; Path = ""; Fields = new Dictionary(); } @@ -58,7 +55,17 @@ namespace refl } public static ClassMeta ParseCppClass(CppClass cppClass) { - ClassMeta cls_meta = new ClassMeta(cppClass.Name); + string parentName = "void"; + if (cppClass.BaseTypes.Count == 1) + { + var type = cppClass.BaseTypes[0].Type; + CppClass? parent = type as CppClass; + if (parent != null) + { + parentName = parent.Name; + } + } + ClassMeta cls_meta = new ClassMeta(cppClass.Name, parentName); foreach (var field in cppClass.Fields) { if (field.Attributes.Count == 0) diff --git a/src/refl/ClassMetaGen.cs b/src/refl/ClassMetaGen.cs index 72954d7..1718501 100644 --- a/src/refl/ClassMetaGen.cs +++ b/src/refl/ClassMetaGen.cs @@ -1,34 +1,120 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; +using System.Text; +using Fluid; namespace refl { + internal class FieldMetaGenData + { + public string Name { get; set; } + public string Meta { get; set; } + public bool IsMethod { get; set; } + + public FieldMetaGenData(string name, string meta, bool isMethod) + { + Name = name; + Meta = meta; + IsMethod = isMethod; + } + } + internal class ClassMetaGenData + { + public string Name { get; set; } = ""; + public string NameSpace { get; set; } = ""; + public string ParentName { get; set; } = ""; + public string Indent { get; set; } = ""; + public string MetaName { get; set; } = ""; + public List FieldList = new List(); + + public ClassMetaGenData(string indent, string nameSpace) + { + Indent = indent; + NameSpace = nameSpace; + } + } + internal class ClassMetaGen { public static Dictionary FileList = new Dictionary(); - public static void GenCppMeta(ModuleMeta module) + public static Fluid.IFluidTemplate? GenTemplate; + public static TemplateOptions GenOptions = new TemplateOptions(); + public static void GenNameMeta() { - foreach(var pair in ModuleMeta.NameMaps) + foreach (var pair in ModuleMeta.NameMaps) { - FileList.Add(pair.Key, new StringBuilder()); - } - foreach(var cls in module.ClassList) - { - + var build = new StringBuilder(); + build.Append("namespace "); + build.Append(pair.Key); + build.Append("_Name {\n"); + foreach(var kv in pair.Value) + { + build.Append(" constexpr const Name "); + build.Append(kv); + build.Append("=\""); + build.Append(kv); + build.Append("\";\n"); + } + build.Append("}\n"); + Console.WriteLine(build.ToString()); + build.Clear(); + FileList.Add(pair.Key, build); } } - public static void GenClassMeta(ModuleMeta module) + public static void GenCppMeta(ModuleMeta module) { + var template_string = File.ReadAllText("template/refl.liquid"); + var parser = new FluidParser(); + parser.TryParse(template_string, out GenTemplate, out var error); + GenOptions.MemberAccessStrategy.Register(); + if (!string.IsNullOrEmpty(error)) + { + Console.WriteLine(error); + return; + } + GenModuleMeta(module, null); + foreach (var pair in FileList) + { + Console.WriteLine(pair.Key); + Console.WriteLine(pair.Value.ToString()); + } + } + public static void GenModuleMeta(ModuleMeta module, string? prefix) + { + var gen = new ClassMetaGenData(prefix+"", module.NameSpace); foreach (var cls in module.ClassList) { - foreach (var field in cls.Fields) + GenClassMeta(cls, gen); + } + foreach (var child in module.ChildList) + { + if(prefix == null) { - + GenModuleMeta(child, prefix + "\r"); } + else + { + GenModuleMeta(child, prefix + "\t"); + } + } + } + public static void GenClassMeta(ClassMeta cls, ClassMetaGenData gen) + { + gen.Name = cls.Name; + gen.ParentName = cls.ParentName; + foreach (var pair in cls.Fields) + { + gen.FieldList.Clear(); + foreach (var field in pair.Value.MemberList) + { + gen.FieldList.Add(new FieldMetaGenData(field.Name, field.Meta, false)); + } + foreach (var field in pair.Value.MethodList) + { + gen.FieldList.Add(new FieldMetaGenData(field.Name, field.Meta, true)); + } + gen.MetaName = pair.Key; + var context = new TemplateContext(gen, GenOptions); + var res = GenTemplate.Render(context); + FileList[pair.Key].Append(res); } } } diff --git a/src/refl/MetaToken.cs b/src/refl/MetaToken.cs index bcceaf0..13a032d 100644 --- a/src/refl/MetaToken.cs +++ b/src/refl/MetaToken.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Text; namespace refl { internal class MetaToken diff --git a/src/refl/Program.cs b/src/refl/Program.cs index 662fc0d..038dbe9 100644 --- a/src/refl/Program.cs +++ b/src/refl/Program.cs @@ -1,9 +1,13 @@ // Parse C++ files -using CppAst; using CommandLine; using refl; - -Parser.Default.ParseArguments(args) +class Program +{ + static void Main(string[] args) + { + Parser.Default.ParseArguments(args) .MapResult( (CmdBuildOption o) => CmdBuildOption.CMD_CheckBuildOption(o), - error => 1); \ No newline at end of file + error => 1); + } +} \ No newline at end of file diff --git a/src/refl/Properties/launchSettings.json b/src/refl/Properties/launchSettings.json index ffe2d10..f6fcd78 100644 --- a/src/refl/Properties/launchSettings.json +++ b/src/refl/Properties/launchSettings.json @@ -2,7 +2,8 @@ "profiles": { "refl": { "commandName": "Project", - "commandLineArgs": "build F:\\csharp\\CppAst.NET\\src\\refl\\cpp\\vertex.h " + "commandLineArgs": "build D:\\csharp\\cppast\\src\\refl\\cpp\\vertex.h ", + "workingDirectory": "D:\\csharp\\cppast\\src\\refl" } } } \ No newline at end of file diff --git a/src/refl/cpp/vertex.h b/src/refl/cpp/vertex.h index e3138ad..d62237d 100644 --- a/src/refl/cpp/vertex.h +++ b/src/refl/cpp/vertex.h @@ -1,6 +1,6 @@ #include using namespace std; -namespace test{ + struct vec3_parent { virtual int norm(int x1, int& x2) { x2 = x1 * x2; @@ -42,5 +42,4 @@ namespace test{ cout << x1 << "::norm3" << endl; } }; -} #include "meta.vertex.inl" \ No newline at end of file diff --git a/src/refl/refl.csproj b/src/refl/refl.csproj index fbb7536..35afad8 100644 --- a/src/refl/refl.csproj +++ b/src/refl/refl.csproj @@ -8,10 +8,12 @@ False $(NETCoreSdkRuntimeIdentifier) + Program + diff --git a/src/refl/template/refl.cpp b/src/refl/template/refl.cpp index bfd110e..78b61b3 100644 --- a/src/refl/template/refl.cpp +++ b/src/refl/template/refl.cpp @@ -19,7 +19,6 @@ struct vec3_Static_Meta { return fetch_meta_size(); } }; -constexpr int size = vec3_Static_Meta::Size(); struct vec3_Meta : public Meta{ using MyStatic = vec3_Static_Meta; using MyUClass = UClass_Meta; diff --git a/src/refl/template/refl.liquid b/src/refl/template/refl.liquid new file mode 100644 index 0000000..19c4a83 --- /dev/null +++ b/src/refl/template/refl.liquid @@ -0,0 +1,48 @@ +{%- assign indent = Indent -%} +{%- if NameSpace != blank -%} + {{ indent }}namespace {{ NameSpace }} { + {% capture newIndent %}{{ indent }} {% endcapture %} + {%- assign indent = newIndent -%} +{%- endif -%} +{{ indent }}struct {{ Name }}_Static_{{MetaName}} { +{{ indent }} consteval static auto __StaticFields() { +{{ indent }} return std::make_tuple({% for field in FieldList %}&{{Name}}::{{field.Name}}{% unless forloop.last %}, {% endunless %}{% endfor %}); +{{ indent }} }; + +{{ indent }} consteval static auto __MakeStaticFields() { +{{ indent }} return std::array{ +{{ indent }} {%- for field in FieldList -%} +{{ indent }} {%- if field.IsMethod -%} +{{ indent }} StaticMethodField(&{{Name}}::{{field.Name}}, {{MetaName}}_Name::{{field.Name}}{% if field.Meta %}, {{field.Meta}}{% endif %}), +{{ indent }} {%- else -%} +{{ indent }} StaticMemberField(&{{Name}}::{{field.Name}}, {{MetaName}}_Name::{{field.Name}}{% if field.Meta %}, {{field.Meta}}{% endif %}), +{{ indent }} {%- endif -%} +{{ indent }} {%- endfor -%} +{{ indent }} }; +{{ indent }} }; + +{{ indent }} consteval static int Size() { +{{ indent }} return fetch_meta_size<{{ Name }}_Static_{{MetaName}}>(); +{{ indent }} }; +{{ indent }}}; + +{{ indent }}struct {{ Name }}_{{MetaName}} : public Meta { +{{ indent }} using MyStatic = {{ Name }}_Static_{{MetaName}}; +{{ indent }} using MyUClass = UClass_Meta<{{ Name }}, {{ ParentName }}>;; +{{ indent }} inline static char s_data[MyStatic::Size()]{}; +{{ indent }} static auto __MakeFields() { +{{ indent }} char* memory = &s_data[0]; +{{ indent }} return std::array{ +{{ indent }} {%- for field in FieldList -%} +{{ indent }} {%- if field.IsMethod -%} +{{ indent }} StaticMethodField(&{{Name}}::{{field.Name}}, {{MetaName}}_Name::{{field.Name}}{% if field.Meta %}, {{field.Meta}}{% endif %}), +{{ indent }} {%- else -%} +{{ indent }} StaticMemberField(&{{Name}}::{{field.Name}}, {{MetaName}}_Name::{{field.Name}}{% if field.Meta %}, {{field.Meta}}{% endif %}), +{{ indent }} {%- endif -%} +{{ indent }} {%- endfor -%} +{{ indent }} }; +{{ indent }} }; +{{ indent }}}; +{% if NameSpace != blank %} +{{ Indent }}} +{% endif %} diff --git a/src/refl/template/test b/src/refl/template/test new file mode 100644 index 0000000..e4b85b6 --- /dev/null +++ b/src/refl/template/test @@ -0,0 +1,52 @@ +{% assign indent = Indent %} +{% if NameSpace %} + {{ indent }}namespace {{ NameSpace }} { + {% capture newIndent %}{{ indent }} {% endcapture %} + {% assign indent = newIndent %} +{% endif %} +{{ indent }}struct {{ Name }}_Static_{{MetaName}} { +{{ indent }} consteval static auto __StaticFields() { +{{ indent }} return std::make_tuple({% for field in FieldList %}&{{Name}}::{{field.Name}}{% unless forloop.last %}, {% endunless %}{% endfor %}); +{{ indent }} }; + +{{ indent }} consteval static auto __MakeStaticFields() { +{{ indent }} return std::array{ +{{ indent }} {% for field in FieldList %} +{{ indent }} {% if field.IsMethod %} +{{ indent }} StaticMethodField(&{{field.Name}}, "{{field.Name}}"{% if field.Meta %}, {{field.Meta}}{% endif %}), +{{ indent }} {% else %} +{{ indent }} StaticMemberField(&{{field.Name}}, "{{field.Name}}"{% if field.Meta %}, {{field.Meta}}{% endif %}), +{{ indent }} {% endif %} +{{ indent }} {% endfor %} +{{ indent }} }; +{{ indent }} }; + +{{ indent }} consteval static int Size() { +{{ indent }} return fetch_meta_size<{{ staticMetaStructName }}>(); +{{ indent }} }; +{{ indent }}}; + +{{ indent }}struct {{ Name }}_{{MetaName}} : public Meta { +{{ indent }} using MyStatic = {{ Name }}_Static_{{MetaName}}; +{{ indent }} using MyUClass = UClass_Meta<{{ Name }}, {{ ParentName }}>;; +{{ indent }} inline static char s_data[MyStatic::Size()]{}; +{{ indent }} static auto __MakeFields() { +{{ indent }} char* memory = &s_data[0]; +{{ indent }} return std::array{ +{{ indent }} {% for field in FieldList %} +{{ indent }} {% if field.IsMethod %} +{{ indent }} StaticMethodField(&{{field.Name}}, "{{field.Name}}"{% if field.Meta %}, {{field.Meta}}{% endif %}), +{{ indent }} {% else %} +{{ indent }} StaticMemberField(&{{field.Name}}, "{{field.Name}}"{% if field.Meta %}, {{field.Meta}}{% endif %}), +{{ indent }} {% endif %} +{{ indent }} {% endfor %} +{{ indent }} }; +{{ indent }} }; +{{ indent }}}; +{% if namespace %} +{% for ns in namespace %} + {{ indent }}} + {% capture newIndent %}{{ indent | slice: 0, -4 }}{% endcapture %} + {% assign indent = newIndent %} +{% endfor %} +{% endif %}