From 8afc2b3e1e1348825ffaffcccf86e6ffeae0c19c Mon Sep 17 00:00:00 2001 From: Deadlocklogic Date: Thu, 14 Dec 2023 08:25:28 +0200 Subject: [PATCH 01/13] Registrable: add folder + start development --- .../Lua/Sol/LuaSolGenerationContext.cs | 10 + .../Registrable/Lua/Sol/LuaSolGenerator.cs | 37 + .../Lua/Sol/LuaSolGeneratorOptions.cs | 12 + .../Registrable/Lua/Sol/LuaSolHeaders.cs | 163 +++++ .../Lua/Sol/LuaSolNamingStrategy.cs | 10 + .../Registrable/Lua/Sol/LuaSolSources.cs | 643 ++++++++++++++++++ .../Registrable/Lua/Sol/LuaSolTypePrinter.cs | 12 + .../RegistrableGeneratorContext.cs | 126 ++++ .../RegistrableGeneratorOptions.cs | 50 ++ .../Registrable/RegistrableInfoEntries.cs | 6 + .../Registrable/RegistrableNamingStrategy.cs | 402 +++++++++++ .../Generators/Registrable/Utils/FQNOption.cs | 44 ++ .../Generators/Registrable/Utils/InfoEntry.cs | 65 ++ .../Generators/Registrable/Utils/InfoMap.cs | 16 + .../Registrable/Utils/InfoMapStack.cs | 71 ++ .../Utils/TemplateParameterOption.cs | 22 + .../Generators/Registrable/Utils/Utils.cs | 19 + 17 files changed, 1708 insertions(+) create mode 100644 src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerationContext.cs create mode 100644 src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs create mode 100644 src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs create mode 100644 src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs create mode 100644 src/Generator/Generators/Registrable/Lua/Sol/LuaSolNamingStrategy.cs create mode 100644 src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs create mode 100644 src/Generator/Generators/Registrable/Lua/Sol/LuaSolTypePrinter.cs create mode 100644 src/Generator/Generators/Registrable/RegistrableGeneratorContext.cs create mode 100644 src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs create mode 100644 src/Generator/Generators/Registrable/RegistrableInfoEntries.cs create mode 100644 src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs create mode 100644 src/Generator/Generators/Registrable/Utils/FQNOption.cs create mode 100644 src/Generator/Generators/Registrable/Utils/InfoEntry.cs create mode 100644 src/Generator/Generators/Registrable/Utils/InfoMap.cs create mode 100644 src/Generator/Generators/Registrable/Utils/InfoMapStack.cs create mode 100644 src/Generator/Generators/Registrable/Utils/TemplateParameterOption.cs create mode 100644 src/Generator/Generators/Registrable/Utils/Utils.cs diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerationContext.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerationContext.cs new file mode 100644 index 000000000..60811553f --- /dev/null +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerationContext.cs @@ -0,0 +1,10 @@ +namespace CppSharp.Generators.Registrable.Lua.Sol +{ + public class LuaSolGenerationContext : RegistrableGeneratorContext + { + public LuaSolGenerationContext() + : base() + { + } + } +} diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs new file mode 100644 index 000000000..db7766ad0 --- /dev/null +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs @@ -0,0 +1,37 @@ +using CppSharp.AST; +using System.Collections.Generic; + +namespace CppSharp.Generators.Registrable.Lua.Sol +{ + + public class LuaSolGenerator : Generator + { + public const string Id = "Lua::Sol"; + public static readonly GeneratorKind Kind = new(Id, "lua::sol", typeof(LuaSolGenerator), typeof(LuaSolTypePrinter), new[] { "lua::sol" }); + + public LuaSolGeneratorOptions GeneratorOptions + { + get; + } + + public LuaSolGenerator(BindingContext context) : base(context) + { + GeneratorOptions = new LuaSolGeneratorOptions(this); + } + + public override List Generate(IEnumerable units) + { + var outputs = new List(); + + var header = new LuaSolHeaders(this, units); + outputs.Add(header); + + var source = new LuaSolSources(this, units); + outputs.Add(source); + + return outputs; + } + + public override bool SetupPasses() => true; + } +} diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs new file mode 100644 index 000000000..158cb47bb --- /dev/null +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs @@ -0,0 +1,12 @@ +namespace CppSharp.Generators.Registrable.Lua.Sol +{ + public class LuaSolGeneratorOptions : RegistrableGeneratorOptions + { + public LuaSolNamingStrategy NamingStrategy; + + public LuaSolGeneratorOptions(LuaSolGenerator generator) : base() + { + NamingStrategy = new LuaSolNamingStrategy(generator); + } + } +} diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs new file mode 100644 index 000000000..78599525f --- /dev/null +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs @@ -0,0 +1,163 @@ +using System.Collections.Generic; +using CppSharp.AST; + +namespace CppSharp.Generators.Registrable.Lua.Sol +{ + public class LuaSolHeaders : LuaSolSources + { + public LuaSolHeaders(LuaSolGenerator generator, IEnumerable units) + : base(generator, units) + { + } + + public override string FileExtension => "h"; + + public override void Process() + { + GenerateFilePreamble(CommentKind.BCPL); + + PushBlock(); + WriteLine("#pragma once"); + PopBlock(NewLineKind.BeforeNextBlock); + + //NewLine(); + //PushBlock(BlockKind.Includes); + //GenerateIncludes(); + //PopBlock(NewLineKind.BeforeNextBlock); + + TranslationUnit.Visit(this); + + //PushBlock(BlockKind.Footer); + //PopBlock(); + + //PushBlock(BlockKind.Class); + //PopBlock(NewLineKind.IfNotEmpty); + + //RegistrableGeneratorContext mycontext = new RegistrableGeneratorContext(); + //string a = (string)mycontext[new InfoEntry("")].Pop(); + } + + #region TranslationUnit + + public virtual void GenerateTranslationUnitNamespaceBegin(TranslationUnit translationUnit) + { + PushBlock(BlockKind.Namespace); + WriteLine($"namespace {TranslationUnit.Module.OutputNamespace} {{"); + } + + public virtual void GenerateTranslationUnitNamespaceEnd(TranslationUnit translationUnit) + { + WriteLine($"}} // namespace {TranslationUnit.Module.OutputNamespace}"); + PopBlock(); + } + + public virtual void GenerateTranslationUnitRegistrationFunctionDeclaration(TranslationUnit translationUnit) + { + NewLine(); + WriteLine(GetTranslationUnitRegistrationFunctionSignature(translationUnit)); + NewLine(); + } + + public virtual void GenerateTranslationUnit(TranslationUnit translationUnit) + { + GenerateTranslationUnitNamespaceBegin(translationUnit); + GenerateTranslationUnitRegistrationFunctionDeclaration(translationUnit); + GenerateTranslationUnitNamespaceEnd(translationUnit); + } + + public virtual bool CanGenerateTranslationUnit(TranslationUnit unit) + { + if (AlreadyVisited(unit)) + { + return false; + } + return true; + } + + public override bool VisitTranslationUnit(TranslationUnit unit) + { + if (!CanGenerateTranslationUnit(unit)) + { + return false; + } + + GenerateTranslationUnit(unit); + + return true; + } + + #endregion + + // + + public virtual void GenerateMain() + { + VisitNamespace(TranslationUnit); + } + + public virtual void GenerateIncludes() + { + foreach (var include in Generator.GeneratorOptions.CommonIncludes) + { + WriteLineIndent(include.ToString()); + } + } + + //public override bool VisitNamespace(Namespace @namespace) + //{ + // base.VisitNamespace(@namespace); + // return true; + //} + + public override bool VisitMethodDecl(Method method) + { + return true; + } + + public override bool VisitFunctionDecl(Function function) + { + //if (FunctionIsTemplate(function)) + //{ + // Console.WriteLine("test"); + //} + return true; + } + + public override bool VisitClassTemplateDecl(ClassTemplate template) + { + return true; + } + + public override bool VisitVariableDecl(Variable variable) + { + return true; + } + + public override bool VisitTypeAliasTemplateDecl(TypeAliasTemplate typeAliasTemplate) + { + return true; + } + + public override bool VisitTypedefNameDecl(TypedefNameDecl typedef) + { + return true; + } + + public override bool VisitFunctionTemplateDecl(FunctionTemplate template) + { + return true; + } + + public static bool FunctionIsTemplate(Function function) + { + foreach (var template in function.Namespace.Templates) + { + if (template.TemplatedDecl == function) + { + return true; + } + } + return false; + } + } +} diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolNamingStrategy.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolNamingStrategy.cs new file mode 100644 index 000000000..2f26269ba --- /dev/null +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolNamingStrategy.cs @@ -0,0 +1,10 @@ +namespace CppSharp.Generators.Registrable.Lua.Sol +{ + public class LuaSolNamingStrategy : RegistrableNamingStrategy + { + public LuaSolNamingStrategy(LuaSolGenerator generator) + : base(generator) + { + } + } +} diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs new file mode 100644 index 000000000..410e3f417 --- /dev/null +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs @@ -0,0 +1,643 @@ +using CppSharp.AST; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace CppSharp.Generators.Registrable.Lua.Sol +{ + public class LuaSolSources : CodeGenerator + { + protected LuaSolGenerator Generator { get; } + protected LuaSolGenerationContext GenerationContext { get; } + protected LuaSolNamingStrategy NamingStrategy => Generator.GeneratorOptions.NamingStrategy; + + public LuaSolSources(LuaSolGenerator generator, IEnumerable units) + : base(generator.Context, units) + { + Generator = generator; + GenerationContext = new LuaSolGenerationContext(); + } + + public override string FileExtension { get { return "cpp"; } } + + protected virtual bool TemplateAllowed { get { return false; } } + + protected bool NonTemplateAllowed { get { return !TemplateAllowed || GenerationContext.PeekTemplateLevel() != 0; } } + + public override void Process() + { + GenerateFilePreamble(CommentKind.BCPL); + + PushBlock(BlockKind.Includes); + var file = Context.Options.GetIncludePath(TranslationUnit); + WriteLine($"#include \"{file}\""); + + NewLine(); + PopBlock(); + + TranslationUnit.Visit(this); + + PushBlock(BlockKind.Footer); + PopBlock(); + } + + public virtual void GenerateDeclarationGlobalStateRegistration(Declaration declaration) + { + if (declaration.Access != AccessSpecifier.Protected) + { + if (declaration.OriginalNamespace is not Class) + { + Write(NamingStrategy.GetBindingContext(declaration, GenerationContext)); + } + else + { + Write($"{NamingStrategy.GetRootContextName(GenerationContext)}[{NamingStrategy.GetBindingIdValue(declaration.Namespace, GenerationContext)}]"); + } + Write($"[{NamingStrategy.GetRegistrationNameQuoted(declaration)}] = "); + Write($"{NamingStrategy.GetRootContextName(GenerationContext)}[{NamingStrategy.GetBindingIdName(declaration)}];"); + NewLine(); + } + } + + public virtual void GenerateDeclarationContainerList(DeclarationContext declaration) + { + List declarations = declaration.Declarations.Where(declaration => declaration is Namespace || declaration is Class || declaration is Enumeration).ToList(); + declarations.Sort((x, y) => x.LineNumberStart.CompareTo(y.LineNumberStart)); + foreach (var item in declarations) + { + item.Visit(this); + }; + } + + #region TranslationUnit + + public virtual string GetTranslationUnitRegistrationFunctionSignature(TranslationUnit translationUnit) + { + StringBuilder builder = new StringBuilder(); + builder.Append("void "); + builder.Append(Generator.GeneratorOptions.NamingStrategy.GetRegistrationFunctionName(translationUnit)); + builder.Append("(::sol::state_view& state) {"); + return builder.ToString(); + } + + public virtual void GenerateTranslationUnitNamespaceBegin(TranslationUnit translationUnit) + { + PushBlock(BlockKind.Namespace); + WriteLine($"namespace {TranslationUnit.Module.OutputNamespace} {{"); + } + + public virtual void GenerateTranslationUnitNamespaceEnd(TranslationUnit translationUnit) + { + WriteLine($"}} // namespace {TranslationUnit.Module.OutputNamespace}"); + PopBlock(); + } + + public virtual void GenerateTranslationUnitRegistrationFunctionBegin(TranslationUnit translationUnit) + { + PushBlock(BlockKind.Function); + NewLine(); + WriteLine(GetTranslationUnitRegistrationFunctionSignature(translationUnit)); + Indent(); + } + + public virtual void GenerateTranslationUnitRegistrationFunctionBody(TranslationUnit translationUnit) + { + GenerateDeclarationContainerList(translationUnit); + } + + public virtual void GenerateTranslationUnitRegistrationFunctionEnd(TranslationUnit translationUnit) + { + Unindent(); + WriteLine("}"); + NewLine(); + PopBlock(NewLineKind.BeforeNextBlock); + } + + public virtual void GenerateTranslationUnit(TranslationUnit translationUnit) + { + GenerateTranslationUnitNamespaceBegin(translationUnit); + GenerateTranslationUnitRegistrationFunctionBegin(translationUnit); + GenerateTranslationUnitRegistrationFunctionBody(translationUnit); + GenerateTranslationUnitRegistrationFunctionEnd(translationUnit); + GenerateTranslationUnitNamespaceEnd(translationUnit); + } + + public virtual bool CanGenerateTranslationUnit(TranslationUnit unit) + { + if (AlreadyVisited(unit)) + { + return false; + } + return true; + } + + public override bool VisitTranslationUnit(TranslationUnit unit) + { + if (!CanGenerateTranslationUnit(unit)) + { + return false; + } + + GenerateTranslationUnit(unit); + + return true; + } + + #endregion + + #region Namespace + + public virtual void GenerateNamespaceDebugName(Namespace @namespace) + { + WriteLine($"/* {NamingStrategy.GetFullyQualifiedName(@namespace, FQNOption.IgnoreNone)} */"); + } + + public virtual void GenerateNamespaceHeader(Namespace @namespace) + { + WriteLine("{"); + Indent(); + } + + public virtual void GenerateNamespaceBegin(Namespace @namespace) + { + Write($"auto {NamingStrategy.GetBindingName(@namespace)} = "); + Write(NamingStrategy.GetBindingContextNamespacePredicate( + NamingStrategy.GetBindingContext(@namespace, GenerationContext), + @namespace.Name) + ); + WriteLine(";"); + } + + public virtual void GenerateNamespaceBody(Namespace @namespace) + { + GenerateNamespaceDeclarationList(@namespace, DetachmentOption.Off); + } + + public virtual void GenerateNamespaceDeclarationList(Namespace @namespace, DetachmentOption detachment) + { + if (detachment == DetachmentOption.Off) + { + GenerateNamespaceFunctions(@namespace); + GenerateNamespaceVariables(@namespace); + } + else + { + GenerateNamespaceContainerList(@namespace); + GenerateNamespaceTemplates(@namespace); + GenerateNamespaceTypedefs(@namespace); + GenerateNamespaceFunctions(@namespace); + GenerateNamespaceVariables(@namespace); + } + } + + public virtual void GenerateNamespaceContainerList(Namespace @namespace) + { + GenerateDeclarationContainerList(@namespace); + } + + public virtual void GenerateNamespaceTemplates(Namespace @namespace) + { + } + + public virtual void GenerateNamespaceTypedefs(Namespace @namespace) + { + } + + public virtual void GenerateNamespaceFunctions(Namespace @namespace) + { + } + + public virtual void GenerateNamespaceVariables(Namespace @namespace) + { + } + + public virtual void GenerateNamespaceEnd(Namespace @namespace) + { + GenerateNamespaceDeclarationList(@namespace, DetachmentOption.On); + } + + public virtual void GenerateNamespaceGlobalStateRegistration(Namespace @namespace) + { + } + + public virtual void GenerateNamespaceFooter(Namespace @namespace) + { + Unindent(); + WriteLine("}"); + } + + public virtual void GenerateNamespace(Namespace @namespace) + { + GenerateNamespaceDebugName(@namespace); + GenerateNamespaceHeader(@namespace); + GenerateNamespaceBegin(@namespace); + GenerateNamespaceBody(@namespace); + GenerateNamespaceEnd(@namespace); + GenerateNamespaceGlobalStateRegistration(@namespace); + GenerateNamespaceFooter(@namespace); + } + + public virtual bool CanGenerateNamespace(Namespace @namespace) + { + // if not self:isNonTemplateAllowed(context) then + // return true + // end + if (AlreadyVisited(@namespace)) + { + return false; + } + else if (@namespace.Access != AccessSpecifier.Public) + { + return false; + } + return @namespace.IsGenerated; + } + + public override bool VisitNamespace(Namespace @namespace) + { + if (!CanGenerateNamespace(@namespace)) + { + return false; + } + + GenerateNamespace(@namespace); + + return true; + } + + #endregion + + #region Enumeration + + public virtual void GenerateEnumDeclItem(Enumeration enumeration, Enumeration.Item item) + { + Write(","); + NewLine(); + Write($"\"{item.Name}\", {NamingStrategy.GetFullyQualifiedName(item, FQNOption.IgnoreNone)}"); + } + + public virtual void GenerateEnumDeclItemList(Enumeration enumeration, List items) + { + foreach (var item in items) + { + GenerateEnumDeclItem(enumeration, item); + } + } + + #region Enumeration Anonymous + + public virtual void GenerateEnumDeclAnonymousItem(Enumeration enumeration, Enumeration.Item item) + { + WriteLine($"{NamingStrategy.GetRootContextName(GenerationContext)}[\"{item.Name}\"] = {item.OriginalName};"); + } + + public virtual void GenerateEnumDeclAnonymousItemList(Enumeration enumeration, List items) + { + foreach (var item in items) + { + GenerateEnumDeclAnonymousItem(enumeration, item); + } + } + + public virtual void GenerateEnumDeclAnonymous(Enumeration enumeration) + { + GenerateEnumDeclAnonymousItemList(enumeration, enumeration.Items); + } + + #endregion + + #region Enumeration Non Scoped + + public virtual void GenerateEnumDeclNonScoped(Enumeration enumeration) + { + GenerateEnumDeclScoped(enumeration); + GenerateEnumDeclAnonymous(enumeration); + } + + #endregion + + #region Enumeration Scoped + + public virtual void GenerateEnumDeclScopedDebugName(Enumeration enumeration) + { + WriteLine($"/* {NamingStrategy.GetFullyQualifiedName(enumeration, FQNOption.IgnoreNone)} */"); + } + + public virtual void GenerateEnumDeclScopedHeader(Enumeration enumeration) + { + WriteLine("{"); + Indent(); + } + + public virtual void GenerateEnumDeclScopedBindingIdName(Enumeration enumeration) + { + WriteLine($"auto {NamingStrategy.GetBindingIdName(enumeration)} = {NamingStrategy.GetBindingIdValue(enumeration, GenerationContext)};"); + } + + public virtual void GenerateEnumDeclScopedBegin(Enumeration enumeration) + { + WriteLine($"auto {NamingStrategy.GetBindingName(enumeration)} = {NamingStrategy.GetRootContextName(GenerationContext)}.new_enum<>("); + Indent(); + Write(NamingStrategy.GetBindingIdName(enumeration)); + } + + public virtual void GenerateEnumDeclScopedItemList(Enumeration enumeration) + { + GenerateEnumDeclItemList(enumeration, enumeration.Items); + } + + public virtual void GenerateEnumDeclScopedBody(Enumeration enumeration) + { + GenerateEnumDeclScopedItemList(enumeration); + GenerateEnumDeclScopedDeclarationList(enumeration, DetachmentOption.Off); + } + + public virtual void GenerateEnumDeclScopedDeclarationList(Enumeration enumeration, DetachmentOption detachment) + { + if (detachment == DetachmentOption.Off) + { + GenerateEnumDeclScopedFunctions(enumeration); + GenerateEnumDeclScopedVariables(enumeration); + } + else + { + GenerateEnumDeclScopedContainerList(enumeration); + GenerateEnumDeclScopedTemplates(enumeration); + GenerateEnumDeclScopedTypedefs(enumeration); + GenerateEnumDeclScopedFunctions(enumeration); + GenerateEnumDeclScopedVariables(enumeration); + } + } + + public virtual void GenerateEnumDeclScopedContainerList(Enumeration enumeration) + { + GenerateDeclarationContainerList(enumeration); + } + + public virtual void GenerateEnumDeclScopedTemplates(Enumeration enumeration) + { + } + + public virtual void GenerateEnumDeclScopedTypedefs(Enumeration enumeration) + { + } + + public virtual void GenerateEnumDeclScopedFunctions(Enumeration enumeration) + { + } + + public virtual void GenerateEnumDeclScopedVariables(Enumeration enumeration) + { + } + + public virtual void GenerateEnumDeclScopedEnd(Enumeration enumeration) + { + Unindent(); + NewLine(); + WriteLine(");"); + GenerateEnumDeclScopedDeclarationList(enumeration, DetachmentOption.On); + } + + public virtual void GenerateEnumDeclScopedGlobalStateRegistration(Enumeration enumeration) + { + GenerateDeclarationGlobalStateRegistration(enumeration); + } + + public virtual void GenerateEnumDeclScopedFooter(Enumeration enumeration) + { + Unindent(); + WriteLine("}"); + } + + public virtual void GenerateEnumDeclScoped(Enumeration enumeration) + { + GenerateEnumDeclScopedDebugName(enumeration); + GenerateEnumDeclScopedHeader(enumeration); + GenerateEnumDeclScopedBindingIdName(enumeration); + GenerateEnumDeclScopedBegin(enumeration); + GenerateEnumDeclScopedBody(enumeration); + GenerateEnumDeclScopedEnd(enumeration); + GenerateEnumDeclScopedGlobalStateRegistration(enumeration); + GenerateEnumDeclScopedFooter(enumeration); + } + + #endregion + + public virtual void GenerateEnumDecl(Enumeration enumeration) + { + if (enumeration.IsScoped) + { + GenerateEnumDeclScoped(enumeration); + } + else + { + if (string.IsNullOrEmpty(enumeration.OriginalName)) + { + GenerateEnumDeclAnonymous(enumeration); + } + else + { + GenerateEnumDeclNonScoped(enumeration); + } + } + } + + public virtual bool CanGenerateEnumDecl(Enumeration enumeration) + { + // if not self:isNonTemplateAllowed(context) then + // return true + // end + if (AlreadyVisited(enumeration)) + { + return false; + } + else if (enumeration.Access != AccessSpecifier.Public) + { + return false; + } + return enumeration.IsGenerated; + } + + public override bool VisitEnumDecl(Enumeration enumeration) + { + if (!CanGenerateEnumDecl(enumeration)) + { + return false; + } + + GenerateEnumDecl(enumeration); + + return true; + } + + #endregion + + #region Class + + public virtual void GenerateClassDeclDebugName(Class @class) + { + WriteLine($"/* {NamingStrategy.GetFullyQualifiedName(@class, FQNOption.IgnoreNone)} */"); + } + + public virtual void GenerateClassDeclHeader(Class @class) + { + WriteLine("{"); + Indent(); + } + + public virtual void GenerateClassDeclBindingIdName(Class @class) + { + WriteLine($"auto {NamingStrategy.GetBindingIdName(@class)} = {NamingStrategy.GetBindingIdValue(@class, GenerationContext)};"); + } + + public virtual void GenerateClassDeclBegin(Class @class) + { + Write($"auto {NamingStrategy.GetBindingName(@class)} = {NamingStrategy.GetRootContextName(GenerationContext)}."); + if (TemplateAllowed) + { + Write("template "); + } + WriteLine($"new_usertype<{NamingStrategy.GetContextualName(@class, GenerationContext, FQNOption.IgnoreNone)}>("); + Indent(); + Write(NamingStrategy.GetBindingIdName(@class)); + } + + public virtual void GenerateClassDeclBody(Class @class) + { + GenerateClassDeclDeclarationList(@class, DetachmentOption.Off); + } + + public virtual void GenerateClassDeclDeclarationList(Class @class, DetachmentOption detachment) + { + if (detachment == DetachmentOption.Off) + { + GenerateClassDeclFunctions(@class); + GenerateClassDeclVariables(@class); + } + else + { + GenerateClassDeclContainerList(@class); + GenerateClassDeclTemplates(@class); + GenerateClassDeclTypedefs(@class); + GenerateClassDeclFunctions(@class); + GenerateClassDeclVariables(@class); + } + } + + public virtual void GenerateClassDeclContainerList(Class @class) + { + GenerateDeclarationContainerList(@class); + } + + public virtual void GenerateClassDeclTemplates(Class @class) + { + } + + public virtual void GenerateClassDeclTypedefs(Class @class) + { + } + + public virtual void GenerateClassDeclFunctions(Class @class) + { + } + + public virtual void GenerateClassDeclVariables(Class @class) + { + } + + public virtual void GenerateClassDeclEnd(Class @class) + { + Unindent(); + NewLine(); + WriteLine(");"); + GenerateClassDeclDeclarationList(@class, DetachmentOption.On); + } + + public virtual void GenerateClassDeclGlobalStateRegistration(Class @class) + { + GenerateDeclarationGlobalStateRegistration(@class); + } + + public virtual void GenerateClassDeclFooter(Class @class) + { + Unindent(); + WriteLine("}"); + } + + public virtual void GenerateClassDecl(Class @class) + { + GenerateClassDeclDebugName(@class); + GenerateClassDeclHeader(@class); + GenerateClassDeclBindingIdName(@class); + GenerateClassDeclBegin(@class); + GenerateClassDeclBody(@class); + GenerateClassDeclEnd(@class); + GenerateClassDeclGlobalStateRegistration(@class); + GenerateClassDeclFooter(@class); + } + + public virtual bool CanGenerateClassDecl(Class @class) + { + if (AlreadyVisited(@class)) + { + return false; + } + else if (@class.Access != AccessSpecifier.Public) + { + return false; + } + else if (!NonTemplateAllowed) + { + return false; + } + else if (Utils.FindDescribedTemplate(@class) != null) + { + return false; + } + return @class.IsGenerated; + } + + public override bool VisitClassDecl(Class @class) + { + if (!CanGenerateClassDecl(@class)) + { + return false; + } + + GenerateClassDecl(@class); + + return true; + } + + #endregion + + public virtual bool CanGenerateConstructor(Method method) + { + // if not self:isNonTemplateAllowed(context) then + // return true + // end + if (AlreadyVisited(method)) + { + return false; + } + else if (method.Access != AccessSpecifier.Public) + { + return false; + } + return method.IsGenerated; + } + + public virtual void GenerateConstructors(Class @class, IEnumerable constructors) + { + var isDetach = GenerationContext.PeekIsDetach(); + + if (isDetach == DetachmentOption.Forced) + { + var filteredConstructors = constructors.Where((method) => CanGenerateConstructor(method)); + foreach (var constructor in constructors) + { + } + } + } + } +} diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolTypePrinter.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolTypePrinter.cs new file mode 100644 index 000000000..c6c5b51b3 --- /dev/null +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolTypePrinter.cs @@ -0,0 +1,12 @@ +using CppSharp.Generators; +using CppSharp.Generators.C; + +namespace CppSharp.Generators.Registrable.Lua.Sol +{ + public class LuaSolTypePrinter : CppTypePrinter + { + public LuaSolTypePrinter(BindingContext context) : base(context) + { + } + } +} diff --git a/src/Generator/Generators/Registrable/RegistrableGeneratorContext.cs b/src/Generator/Generators/Registrable/RegistrableGeneratorContext.cs new file mode 100644 index 000000000..25c1c9ce1 --- /dev/null +++ b/src/Generator/Generators/Registrable/RegistrableGeneratorContext.cs @@ -0,0 +1,126 @@ +namespace CppSharp.Generators.Registrable +{ + public class RegistrableGeneratorContext : InfoMapStack + { + public static readonly InfoEntry IndentLevel = new("CppSharp.Generators.Registrable.IndentLevel"); + public static readonly InfoEntry IsDetach = new("CppSharp.Generators.Registrable.IsDetach"); + public static readonly InfoEntry RootContextName = new("CppSharp.Generators.Registrable.RootContextName"); + public static readonly InfoEntry BindingContext = new("CppSharp.Generators.Registrable.BindingContext"); + public static readonly InfoEntry CppContext = new("CppSharp.Generators.Registrable.CppContext"); + public static readonly InfoEntry SanitizeType = new("CppSharp.Generators.Registrable.SanitizeType"); + public static readonly InfoEntry TypeArgumentsPack = new("CppSharp.Generators.Registrable.TypeArgumentsPack"); + public static readonly InfoEntry Resolvable = new("CppSharp.Generators.Registrable.Resolvable"); + public static readonly InfoEntry TemplateLevel = new("CppSharp.Generators.Registrable.TemplateLevel"); + + public RegistrableGeneratorContext() + { + } + + public DetachmentOption PeekIsDetach() + { + return PeekIsDetach(DetachmentOption.Off); + } + + public DetachmentOption PeekIsDetach(DetachmentOption defaultValue) + { + return Peek(IsDetach, defaultValue); + } + + public void PushIsDetach(DetachmentOption item) + { + Push(IsDetach, item); + } + + public DetachmentOption PopIsDetach() + { + return Pop(IsDetach); + } + + public string PeekRootContextName(string defaultValue = default) + { + return Peek(RootContextName, defaultValue); + } + + public void PushRootContextName(string item) + { + Push(RootContextName, item); + } + + public string PopRootContextName() + { + return Pop(RootContextName); + } + + public string PeekBindingContext(string defaultValue = default) + { + return Peek(BindingContext, defaultValue); + } + + public void PushBindingContext(string item) + { + Push(BindingContext, item); + } + + public string PopBindingContext() + { + return Pop(BindingContext); + } + + public CppContext PeekCppContext(CppContext defaultValue = default) + { + return Peek(CppContext, defaultValue); + } + + public void PushCppContext(CppContext item) + { + Push(CppContext, item); + } + + public CppContext PopCppContext() + { + return Pop(CppContext); + } + + public int PeekTemplateLevel(int defaultValue = default) + { + return Peek(TemplateLevel, defaultValue); + } + + public void PushTemplateLevel(int item) + { + Push(TemplateLevel, item); + } + + public int PopTemplateLevel() + { + return Pop(TemplateLevel); + } + } + + public class CppContext + { + public string FullyQualifiedName { get; set; } + public FQNOption Option { get; set; } + + public string GetFullQualifiedName(FQNOption option) + { + if (!(Option | option).IgnoreTemplateTypenameKeyword) + { + return "typename " + FullyQualifiedName; + } + return FullyQualifiedName; + } + + public string GetFullQualifiedName() + { + return GetFullQualifiedName(FQNOption.IgnoreNone); + } + }; + + public enum DetachmentOption + { + On, + Off, + Forced + } +} diff --git a/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs b/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs new file mode 100644 index 000000000..7e7e82d13 --- /dev/null +++ b/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs @@ -0,0 +1,50 @@ +using CppSharp.Generators.C; +using System.Collections.Generic; + +namespace CppSharp.Generators.Registrable +{ + public abstract class RegistrableGeneratorOptions + { + public delegate string Delegate(string name); + + protected Generator generator; + public virtual ISet CommonIncludes { get; } + public virtual string OutputSubDir { get; } + public Delegate BindingIdNamePredicate { get; } + public Delegate BindingIdValuePredicate { get; } + public Delegate BindingNamePredicate { get; } + + public RegistrableGeneratorOptions() + { + CommonIncludes = new HashSet(); + OutputSubDir = null; + BindingIdNamePredicate = DefaultBindingIdNamePredicate(); + BindingIdValuePredicate = DefaultBindingIdValuePredicate(); + BindingNamePredicate = DefaultBindingNamePredicate(); + } + + public virtual Delegate DefaultBindingIdNamePredicate() + { + return (string name) => + { + return $"_cppbind_id_{name}"; + }; + } + + public virtual Delegate DefaultBindingIdValuePredicate() + { + return (string name) => + { + return $"typeid({name}).name()"; + }; + } + + public virtual Delegate DefaultBindingNamePredicate() + { + return (string name) => + { + return $"_cppbind_{name}"; + }; + } + } +} diff --git a/src/Generator/Generators/Registrable/RegistrableInfoEntries.cs b/src/Generator/Generators/Registrable/RegistrableInfoEntries.cs new file mode 100644 index 000000000..35e384057 --- /dev/null +++ b/src/Generator/Generators/Registrable/RegistrableInfoEntries.cs @@ -0,0 +1,6 @@ +namespace CppSharp.Generators.Registrable +{ + public class RegistrableInfoEntries + { + } +} diff --git a/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs b/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs new file mode 100644 index 000000000..9d8bb7f72 --- /dev/null +++ b/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs @@ -0,0 +1,402 @@ +using CppSharp.AST; +using CppSharp.Generators.C; +using CppSharp.Generators.Registrable.Lua.Sol; +using System.Collections.Generic; +using System.Text; +using System.Xml.Linq; + +namespace CppSharp.Generators.Registrable +{ + public class RegistrableNamingStrategy where T : LuaSolGenerator + { + protected T Generator; + + public RegistrableNamingStrategy(T generator) + { + Generator = generator; + } + + public bool IsNestedTemplate(Declaration declaration) + { + var currentDeclaration = declaration; + while (true) + { + currentDeclaration = currentDeclaration.OriginalNamespace; + if (currentDeclaration != null || currentDeclaration is TranslationUnit) + { + break; + } + if (Utils.FindDescribedTemplate(currentDeclaration) != null) + { + return true; + } + } + return false; + } + + public virtual string PrintClassTemplateParameter(Declaration declaration, TemplateParameterOption option) + { + var builder = new StringBuilder(); + if (declaration is TypeTemplateParameter typeTemplateParameter) + { + if (!option.IgnoreKeyword) + { + builder.Append("typename"); + if (typeTemplateParameter.IsParameterPack) + { + builder.Append("..."); + } + } + if (!string.IsNullOrEmpty(typeTemplateParameter.OriginalName)) + { + if (!option.IgnoreKeyword) + { + builder.Append(' '); + } + if (option.CustomPrefix != null) + { + builder.Append(option.CustomPrefix); + } + builder.Append(typeTemplateParameter.OriginalName); + } + if (!option.IgnoreKeyword) + { + if (!option.IgnoreDefault) + { + if (typeTemplateParameter.DefaultArgument.Type != null) + { + builder.Append(" = "); + builder.Append(typeTemplateParameter.DefaultArgument.Type.Visit(new CppTypePrinter(Generator.Context))); + } + } + } + else + { + if (typeTemplateParameter.IsParameterPack) + { + builder.Append("..."); + } + } + } + else if (declaration is NonTypeTemplateParameter nonTypeTemplateParameter) + { + if (!option.IgnoreKeyword) + { + builder.Append(nonTypeTemplateParameter.Type.Visit(new CppTypePrinter(Generator.Context))); + if (nonTypeTemplateParameter.IsParameterPack) + { + builder.Append("..."); + } + } + if (!string.IsNullOrEmpty(nonTypeTemplateParameter.OriginalName)) + { + if (!option.IgnoreKeyword) + { + builder.Append(' '); + } + if (option.CustomPrefix != null) + { + builder.Append(option.CustomPrefix); + } + builder.Append(nonTypeTemplateParameter.OriginalName); + } + if (!option.IgnoreKeyword) + { + if (!option.IgnoreDefault) + { + if (nonTypeTemplateParameter.DefaultArgument != null) + { + builder.Append(" = "); + builder.Append(nonTypeTemplateParameter.DefaultArgument.ToString()); + } + } + } + else + { + if (nonTypeTemplateParameter.IsParameterPack) + { + builder.Append("..."); + } + } + } + return builder.ToString(); + } + + public virtual string PrintClassTemplateParameters(ClassTemplate classTemplate, bool includeEnclosingBrackets, TemplateParameterOption option) + { + var builder = new StringBuilder(); + builder.Append('<'); + for (int i = 0; i < classTemplate.Parameters.Count; i++) + { + if (i > 0) + { + builder.Append(", "); + } + builder.Append(PrintClassTemplateParameter(classTemplate.Parameters[i], option)); + } + builder.Append('>'); + return builder.ToString(); + } + + public virtual string PrintClassTemplateSpecializationArgument(TemplateArgument templateArgument) + { + if (templateArgument.Kind == TemplateArgument.ArgumentKind.Integral) + { + return templateArgument.Integral.ToString(); + } + return templateArgument.Type.Type.Visit(new CppTypePrinter(Generator.Context)); + } + + public virtual string PrintClassTemplateSpecializationArguments(ClassTemplateSpecialization classTemplateSpecialization, bool includeEnclosingBrackets) + { + var builder = new StringBuilder(); + builder.Append('<'); + for (int i = 0; i < classTemplateSpecialization.Arguments.Count; i++) + { + if (i > 0) + { + builder.Append(", "); + } + builder.Append(PrintClassTemplateSpecializationArgument(classTemplateSpecialization.Arguments[i])); + } + builder.Append('>'); + return builder.ToString(); + } + + public virtual string GetQualifiedName(Declaration declaration, FQNOption option) + { + if (declaration is TranslationUnit) + { + return ""; + } + + var name = declaration.OriginalName; + var currentDeclaration = declaration; + + if (currentDeclaration is ClassTemplateSpecialization specialization) + { + if (!option.IgnoreTemplateParameters) + { + name = ($"{name}{PrintClassTemplateSpecializationArguments(specialization, true)}"); + } + } + else + { + if (currentDeclaration is not ClassTemplate template) + { + template = (ClassTemplate)Utils.FindDescribedTemplate(currentDeclaration); + } + if (template != null) + { + if (!option.IgnoreTemplateParameters) + { + name = ($"{name}{PrintClassTemplateParameters(template, true, TemplateParameterOption.AsArgument)}"); + } + } + } + + return name; + } + + public virtual string GetFullyQualifiedName(Declaration declaration, FQNOption option) + { + if (declaration is TranslationUnit) + { + return ""; + } + + var name = new StringBuilder(); + var currentDeclaration = declaration; + var needsTypename = false; + var depth = 0; + + while (true) + { + if (currentDeclaration == null || currentDeclaration is TranslationUnit) + { + break; + } + depth += 1; + var currentName = new StringBuilder(); + currentName.Append(currentDeclaration.OriginalName); + + if (currentDeclaration is ClassTemplateSpecialization specialization) + { + if (!option.IgnoreTemplateTemplateKeyword) + { + if (IsNestedTemplate(currentDeclaration)) + { + currentName.Insert(0, "template "); + } + } + if (!option.IgnoreTemplateParameters) + { + if (depth > 1) + { + needsTypename = true; + } + currentName.Append(PrintClassTemplateSpecializationArguments(specialization, true)); + } + } + else + { + if (currentDeclaration is not ClassTemplate template) + { + template = (ClassTemplate)Utils.FindDescribedTemplate(currentDeclaration); + } + if (template != null) + { + if (!option.IgnoreTemplateTemplateKeyword) + { + if (IsNestedTemplate(currentDeclaration)) + { + currentName.Insert(0, "template "); + } + } + if (!option.IgnoreTemplateParameters) + { + if (depth > 1) + { + needsTypename = true; + } + currentName.Append($"{name}{PrintClassTemplateParameters(template, true, TemplateParameterOption.AsArgument)}"); + } + } + } + + if (name.Length != 0) + { + name.Insert(0, "::"); + } + name.Insert(0, currentName); + currentDeclaration = currentDeclaration.OriginalNamespace; + } + if (!option.IgnoreGlobalNamespace) + { + name.Insert(0, "::"); + } + if (!option.IgnoreTemplateTypenameKeyword) + { + if (needsTypename) + { + name.Insert(0, "typename "); + } + } + + return name.ToString(); + } + + public virtual string GetContextualName(Declaration declaration, RegistrableGeneratorContext context, FQNOption option) + { + return GetCppContext(declaration, context, new FQNOption(false, true, false, false)) + "::" + GetQualifiedName(declaration, option); + } + + public virtual string GetRegistrationFunctionName(Declaration declaration, bool isRecusrive = false) + { + if (declaration is TranslationUnit translationUnit) + { + return isRecusrive ? "" : $"register_{translationUnit.FileNameWithoutExtension}"; + } + + var name = declaration.OriginalName; + var currentDeclaration = declaration; + while (true) + { + currentDeclaration = currentDeclaration.OriginalNamespace; + if (currentDeclaration == null || currentDeclaration is TranslationUnit) + { + break; + } + name = currentDeclaration.OriginalName + "_" + name; + } + return name; + } + + public virtual string GetRegistrationNameQuoted(Declaration declaration) + { + return $"\"{declaration.Name}\""; + } + + public virtual string GetBindingIdName(Declaration declaration) + { + return Generator.GeneratorOptions.BindingIdNamePredicate(GetRegistrationFunctionName(declaration)); + } + + public virtual string GetBindingIdValue(Declaration declaration, RegistrableGeneratorContext context) + { + return Generator.GeneratorOptions.BindingIdValuePredicate(GetContextualName(declaration, context, FQNOption.IgnoreNone)); + } + + public virtual string GetBindingName(Declaration declaration) + { + return Generator.GeneratorOptions.BindingNamePredicate(GetRegistrationFunctionName(declaration)); + } + + public virtual string GetRootContextName(RegistrableGeneratorContext context) + { + if (context != null) + { + var rootContextName = context.PeekRootContextName(); + if (rootContextName != null) + { + return rootContextName; + } + } + return "state"; + } + + public virtual string GetBindingContextNamespacePredicate(string state, string key) + { + return $"get_namespace({state}, \"{key}\")"; + } + + public virtual string GetBindingContext(Declaration declaration, RegistrableGeneratorContext context) + { + if (context != null) + { + var rootContextName = context.PeekRootContextName(); + if (rootContextName != null) + { + return rootContextName; + } + } + if (declaration.Namespace is TranslationUnit) + { + return GetRootContextName(context); + } + else + { + var name = GetRootContextName(context); + var currentDeclaration = declaration.Namespace; + var parentList = new List(); + while (true) + { + if (currentDeclaration != null || currentDeclaration is TranslationUnit) + { + break; + } + parentList.Insert(0, currentDeclaration); + currentDeclaration = currentDeclaration.Namespace; + } + foreach (var parent in parentList) + { + name = GetBindingContextNamespacePredicate(name, parent.Name); + } + return name; + } + } + + public string GetCppContext(Declaration entity, RegistrableGeneratorContext context, FQNOption option) + { + if (context != null) + { + var cppContext = context.PeekCppContext(); + if (cppContext != null) + { + return cppContext.GetFullQualifiedName(option); + } + } + return "";// GetFullyQualifiedName(entity.OriginalNamespace, option, context); + } + } +} diff --git a/src/Generator/Generators/Registrable/Utils/FQNOption.cs b/src/Generator/Generators/Registrable/Utils/FQNOption.cs new file mode 100644 index 000000000..026b0a93a --- /dev/null +++ b/src/Generator/Generators/Registrable/Utils/FQNOption.cs @@ -0,0 +1,44 @@ +namespace CppSharp.Generators.Registrable +{ + public class FQNOption + { + public static readonly FQNOption IgnoreNone = new(false, false, false, false); + public static readonly FQNOption IgnoreAll = new(true, true, true, true); + + public bool IgnoreGlobalNamespace { get; set; } + public bool IgnoreTemplateTypenameKeyword { get; set; } + public bool IgnoreTemplateTemplateKeyword { get; set; } + public bool IgnoreTemplateParameters { get; set; } + + public FQNOption(bool ignoreGlobalNamespace = false, + bool ignoreTemplateTypenameKeyword = false, + bool ignoreTemplateTemplateKeyword = false, + bool ignoreTemplateParameters = false) + { + IgnoreGlobalNamespace = ignoreGlobalNamespace; + IgnoreTemplateTypenameKeyword = ignoreTemplateTypenameKeyword; + IgnoreTemplateTemplateKeyword = ignoreTemplateTemplateKeyword; + IgnoreTemplateParameters = ignoreTemplateParameters; + } + + public static FQNOption operator |(FQNOption lhs, FQNOption rhs) + { + return new FQNOption( + lhs.IgnoreGlobalNamespace | rhs.IgnoreGlobalNamespace, + lhs.IgnoreTemplateTypenameKeyword | rhs.IgnoreTemplateTypenameKeyword, + lhs.IgnoreTemplateTemplateKeyword | rhs.IgnoreTemplateTemplateKeyword, + lhs.IgnoreTemplateParameters | rhs.IgnoreTemplateParameters + ); + } + + public static FQNOption operator &(FQNOption lhs, FQNOption rhs) + { + return new FQNOption( + lhs.IgnoreGlobalNamespace & rhs.IgnoreGlobalNamespace, + lhs.IgnoreTemplateTypenameKeyword & rhs.IgnoreTemplateTypenameKeyword, + lhs.IgnoreTemplateTemplateKeyword & rhs.IgnoreTemplateTemplateKeyword, + lhs.IgnoreTemplateParameters & rhs.IgnoreTemplateParameters + ); + } + } +} diff --git a/src/Generator/Generators/Registrable/Utils/InfoEntry.cs b/src/Generator/Generators/Registrable/Utils/InfoEntry.cs new file mode 100644 index 000000000..b2055b901 --- /dev/null +++ b/src/Generator/Generators/Registrable/Utils/InfoEntry.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace CppSharp.Generators.Registrable +{ + public class InfoEntry : IEquatable + { + public static readonly HashSet Registered = new(); + + public string Name { get; } + + public InfoEntry(string name) + { + if (Registered.Any(kind => kind.Name == name)) + { + throw new Exception($"InfoEntry has an already registered name: {Name}"); + } + Name = name; + Registered.Add(this); + } + + public static bool operator ==(InfoEntry obj1, InfoEntry obj2) + { + if (ReferenceEquals(obj1, obj2)) + { + return true; + } + if (obj1 is null) + { + return false; + } + if (obj2 is null) + { + return false; + } + return obj1.Equals(obj2); + } + + public static bool operator !=(InfoEntry obj1, InfoEntry obj2) => !(obj1 == obj2); + + public bool Equals(InfoEntry other) + { + if (other is null) + { + return false; + } + if (ReferenceEquals(this, other)) + { + return true; + } + return Name.Equals(other.Name); + } + + public override bool Equals(object obj) => Equals(obj as InfoEntry); + + public override int GetHashCode() + { + unchecked + { + return Name.GetHashCode(); + } + } + } +} diff --git a/src/Generator/Generators/Registrable/Utils/InfoMap.cs b/src/Generator/Generators/Registrable/Utils/InfoMap.cs new file mode 100644 index 000000000..3017d00a1 --- /dev/null +++ b/src/Generator/Generators/Registrable/Utils/InfoMap.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace CppSharp.Generators.Registrable +{ + public class InfoMap : Dictionary + { + public InfoMap() : base() + { + } + + public T1 Get(InfoEntry infoEntry) where T1 : T + { + return (T1)this[infoEntry]; + } + } +} diff --git a/src/Generator/Generators/Registrable/Utils/InfoMapStack.cs b/src/Generator/Generators/Registrable/Utils/InfoMapStack.cs new file mode 100644 index 000000000..2677386d7 --- /dev/null +++ b/src/Generator/Generators/Registrable/Utils/InfoMapStack.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; + +namespace CppSharp.Generators.Registrable +{ + public class InfoMapStack : InfoMap> + { + public InfoMapStack() : base() + { + } + + public T1 Peek(InfoEntry infoEntry, T1 defaultValue = default) where T1 : T + { + if (TryGetValue(infoEntry, out Stack stack)) + { + return (T1)stack.Peek(); + } + return defaultValue; + } + + public T1 Pop(InfoEntry infoEntry) where T1 : T + { + if (TryGetValue(infoEntry, out Stack stack)) + { + return (T1)stack.Pop(); + } + throw new InvalidOperationException(); + } + + public void Push(InfoEntry infoEntry, T1 item) where T1 : T + { + if (!TryGetValue(infoEntry, out Stack stack)) + { + this[infoEntry] = stack = new Stack(); + } + stack.Push(item); + } + + public bool TryPeek(InfoEntry infoEntry, [MaybeNullWhen(false)] out T1 result) where T1 : T + { + if (TryGetValue(infoEntry, out Stack stack)) + { + bool tempReturn = stack.TryPop(out T tempResult); + result = (T1)tempResult; + return tempReturn; + } + result = default; + return false; + } + + public bool TryPop(InfoEntry infoEntry, [MaybeNullWhen(false)] out T1 result) where T1 : T + { + if (TryGetValue(infoEntry, out Stack stack)) + { + bool tempReturn = stack.TryPop(out T tempResult); + result = (T1)tempResult; + return tempReturn; + } + result = default; + return false; + } + + public void Scoped(InfoEntry infoEntry, T1 item, Action action) where T1 : T + { + Push(infoEntry, item); + action(); + Pop(infoEntry); + } + } +} diff --git a/src/Generator/Generators/Registrable/Utils/TemplateParameterOption.cs b/src/Generator/Generators/Registrable/Utils/TemplateParameterOption.cs new file mode 100644 index 000000000..db32620e8 --- /dev/null +++ b/src/Generator/Generators/Registrable/Utils/TemplateParameterOption.cs @@ -0,0 +1,22 @@ +namespace CppSharp.Generators.Registrable +{ + public class TemplateParameterOption + { + public static readonly TemplateParameterOption AsParameter = new(false, false); + public static readonly TemplateParameterOption AsParameterNoDefault = new(false, true); + public static readonly TemplateParameterOption AsArgument = new(true, true); + + public bool IgnoreKeyword { get; set; } + public bool IgnoreDefault { get; set; } + public string CustomPrefix { get; set; } + + TemplateParameterOption(bool ignoreKeyword = false, + bool ignoreDefault = false, + string customPrefix = "") + { + IgnoreKeyword = ignoreKeyword; + IgnoreDefault = ignoreDefault; + CustomPrefix = customPrefix; + } + } +} diff --git a/src/Generator/Generators/Registrable/Utils/Utils.cs b/src/Generator/Generators/Registrable/Utils/Utils.cs new file mode 100644 index 000000000..cff813105 --- /dev/null +++ b/src/Generator/Generators/Registrable/Utils/Utils.cs @@ -0,0 +1,19 @@ +using CppSharp.AST; + +namespace CppSharp.Generators.Registrable +{ + public static class Utils + { + public static Declaration FindDescribedTemplate(Declaration declaration) + { + foreach (var template in declaration.Namespace.Templates) + { + if (template.TemplatedDecl == declaration) + { + return template; + } + } + return null; + } + } +} From c86106abaf742f0127504067dd362c659d13f971 Mon Sep 17 00:00:00 2001 From: Deadlocklogic Date: Thu, 14 Dec 2023 10:51:19 +0200 Subject: [PATCH 02/13] Registrable: add support for field/variable --- .../Registrable/Lua/Sol/LuaSolSources.cs | 247 +++++++++++++++++- .../Registrable/RegistrableNamingStrategy.cs | 2 +- .../Registrable/Utils/InfoMapStack.cs | 7 +- .../Generators/Registrable/Utils/Utils.cs | 5 + 4 files changed, 248 insertions(+), 13 deletions(-) diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs index 410e3f417..24e88cafa 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs @@ -1,4 +1,5 @@ using CppSharp.AST; +using CppSharp.Generators.C; using System.Collections.Generic; using System.Linq; using System.Text; @@ -103,6 +104,14 @@ public virtual void GenerateTranslationUnitRegistrationFunctionBegin(Translation public virtual void GenerateTranslationUnitRegistrationFunctionBody(TranslationUnit translationUnit) { GenerateDeclarationContainerList(translationUnit); + + GenerationContext.Scoped(RegistrableGeneratorContext.IsDetach, DetachmentOption.On, () => + { + foreach (var variable in translationUnit.Variables) + { + variable.Visit(this); + } + }); } public virtual void GenerateTranslationUnitRegistrationFunctionEnd(TranslationUnit translationUnit) @@ -175,19 +184,14 @@ public virtual void GenerateNamespaceBody(Namespace @namespace) public virtual void GenerateNamespaceDeclarationList(Namespace @namespace, DetachmentOption detachment) { - if (detachment == DetachmentOption.Off) - { - GenerateNamespaceFunctions(@namespace); - GenerateNamespaceVariables(@namespace); - } - else + GenerateNamespaceContainerList(@namespace); + GenerateNamespaceTemplates(@namespace); + GenerateNamespaceTypedefs(@namespace); + GenerationContext.Scoped(RegistrableGeneratorContext.IsDetach, DetachmentOption.On, () => { - GenerateNamespaceContainerList(@namespace); - GenerateNamespaceTemplates(@namespace); - GenerateNamespaceTypedefs(@namespace); GenerateNamespaceFunctions(@namespace); GenerateNamespaceVariables(@namespace); - } + }); } public virtual void GenerateNamespaceContainerList(Namespace @namespace) @@ -209,6 +213,10 @@ public virtual void GenerateNamespaceFunctions(Namespace @namespace) public virtual void GenerateNamespaceVariables(Namespace @namespace) { + foreach (var variable in @namespace.Variables) + { + variable.Visit(this); + } } public virtual void GenerateNamespaceEnd(Namespace @namespace) @@ -543,6 +551,14 @@ public virtual void GenerateClassDeclFunctions(Class @class) public virtual void GenerateClassDeclVariables(Class @class) { + foreach (var field in @class.Fields) + { + field.Visit(this); + } + foreach (var variable in @class.Variables) + { + variable.Visit(this); + } } public virtual void GenerateClassDeclEnd(Class @class) @@ -611,6 +627,217 @@ public override bool VisitClassDecl(Class @class) #endregion + #region Field + + #region Field + + public virtual bool CanGenerateFieldDecl(Field field) + { + if (AlreadyVisited(field)) + { + return false; + } + else if (field.Access != AccessSpecifier.Public) + { + return false; + } + else if (!NonTemplateAllowed) + { + return false; + } + return field.IsGenerated; + } + + public virtual bool GenerateFieldDecl(Field field) + { + var isDetach = GenerationContext.PeekIsDetach(DetachmentOption.Off); + + if (isDetach == DetachmentOption.Forced || isDetach == Utils.FindDetachmentOption(field)) + { + string fieldName = field.Name; + string fieldNameQuoted = $"\"{fieldName}\""; + string fieldContextualName = NamingStrategy.GetContextualName(field, GenerationContext, FQNOption.IgnoreNone); + + if (isDetach != DetachmentOption.Off) + { + Write($"{NamingStrategy.GetBindingContext(field, GenerationContext)}[{fieldNameQuoted}] = "); + } + else + { + WriteLine(","); + Write($"{fieldNameQuoted}, "); + } + // TODO : check for typemaps!!! + { + Write($"&{fieldContextualName}"); + } + if (isDetach != DetachmentOption.Off) + { + WriteLine(";"); + } + } + + return true; + } + + #endregion + + #region Bitfield + + public virtual bool CanGenerateFieldDeclBitfield(Field field) + { + if (AlreadyVisited(field)) + { + return false; + } + else if (field.Access != AccessSpecifier.Public) + { + return false; + } + else if (!NonTemplateAllowed) + { + return false; + } + return field.IsGenerated; + } + + public virtual bool GenerateFieldDeclBitfield(Field field) + { + var isDetach = GenerationContext.PeekIsDetach(DetachmentOption.Off); + + if (isDetach == DetachmentOption.Forced || isDetach == Utils.FindDetachmentOption(field)) + { + string bitfieldOriginalName = field.OriginalName; + string bitfieldName = field.Name; + string bitfieldNameQuoted = $"\"{bitfieldName}\""; + string bitfieldCppContext = NamingStrategy.GetCppContext(field, GenerationContext, FQNOption.IgnoreNone); + string bitfieldType = field.Type.Visit(new CppTypePrinter(Context)); + + if (isDetach != DetachmentOption.Off) + { + Write($"{NamingStrategy.GetBindingContext(field, GenerationContext)}[{bitfieldNameQuoted}] = "); + } + else + { + WriteLine(","); + Write($"{bitfieldNameQuoted}, "); + } + WriteLine("::sol::property("); + Indent(); + WriteLine($"[]({bitfieldCppContext}& self) {{"); + Indent(); + WriteLine($"return self.{bitfieldOriginalName};"); + Unindent(); + WriteLine("}, "); + WriteLine($"[]({bitfieldCppContext}& self, {bitfieldType} value) {{"); + Indent(); + WriteLine($"self.{bitfieldOriginalName} = value;"); + Unindent(); + WriteLine("}"); + Unindent(); + Write(")"); + if (isDetach != DetachmentOption.Off) + { + WriteLine(";"); + } + } + + return true; + } + + #endregion + + public override bool VisitFieldDecl(Field field) + { + if (field.IsBitField) + { + if (!CanGenerateFieldDeclBitfield(field)) + { + return false; + } + + return GenerateFieldDeclBitfield(field); + } + else + { + if (!CanGenerateFieldDecl(field)) + { + return false; + } + + return GenerateFieldDecl(field); + } + return false; + } + + #endregion + + #region Variable + + public virtual bool CanGenerateVariableDecl(Variable variable) + { + if (AlreadyVisited(variable)) + { + return false; + } + else if (variable.Access != AccessSpecifier.Public) + { + return false; + } + else if (!NonTemplateAllowed) + { + return false; + } + return variable.IsGenerated; + } + + public virtual bool GenerateVariableDecl(Variable variable) + { + var isDetach = GenerationContext.PeekIsDetach(DetachmentOption.Off); + + if (isDetach == DetachmentOption.Forced || isDetach == Utils.FindDetachmentOption(variable)) + { + string variableName = variable.Name; + string variableNameQuoted = $"\"{variableName}\""; + string variableBindingContext = NamingStrategy.GetBindingContext(variable, GenerationContext); + string variableContextualName = NamingStrategy.GetContextualName(variable, GenerationContext, FQNOption.IgnoreNone); + // TODO: Bug in sol until it gets resolved: we can only bind static class variable by reference. + if (variable.OriginalNamespace is Class) + { + variableContextualName = $"::std::ref({variableContextualName})"; + } + + // TODO: check for typemaps!!! + if (isDetach != DetachmentOption.Off) + { + Write($"{variableBindingContext}[{variableNameQuoted}] = ::sol::var({variableContextualName});"); + } + else + { + WriteLine(","); + Write($"{variableNameQuoted}, ::sol::var({variableContextualName})"); + } + if (isDetach != DetachmentOption.Off) + { + WriteLine(";"); + } + } + + return true; + } + + public override bool VisitVariableDecl(Variable variable) + { + if (!CanGenerateVariableDecl(variable)) + { + return false; + } + + return GenerateVariableDecl(variable); + } + + #endregion + public virtual bool CanGenerateConstructor(Method method) { // if not self:isNonTemplateAllowed(context) then diff --git a/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs b/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs index 9d8bb7f72..fe7a4537e 100644 --- a/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs +++ b/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs @@ -396,7 +396,7 @@ public string GetCppContext(Declaration entity, RegistrableGeneratorContext cont return cppContext.GetFullQualifiedName(option); } } - return "";// GetFullyQualifiedName(entity.OriginalNamespace, option, context); + return GetFullyQualifiedName(entity.OriginalNamespace, option); } } } diff --git a/src/Generator/Generators/Registrable/Utils/InfoMapStack.cs b/src/Generator/Generators/Registrable/Utils/InfoMapStack.cs index 2677386d7..2fec16530 100644 --- a/src/Generator/Generators/Registrable/Utils/InfoMapStack.cs +++ b/src/Generator/Generators/Registrable/Utils/InfoMapStack.cs @@ -14,7 +14,10 @@ public T1 Peek(InfoEntry infoEntry, T1 defaultValue = default) where T1 : T { if (TryGetValue(infoEntry, out Stack stack)) { - return (T1)stack.Peek(); + if (stack.Count > 0) + { + return (T1)stack.Peek(); + } } return defaultValue; } @@ -61,7 +64,7 @@ public bool TryPop(InfoEntry infoEntry, [MaybeNullWhen(false)] out T1 result return false; } - public void Scoped(InfoEntry infoEntry, T1 item, Action action) where T1 : T + public void Scoped(InfoEntry infoEntry, T item, Action action) { Push(infoEntry, item); action(); diff --git a/src/Generator/Generators/Registrable/Utils/Utils.cs b/src/Generator/Generators/Registrable/Utils/Utils.cs index cff813105..ef03bbb5c 100644 --- a/src/Generator/Generators/Registrable/Utils/Utils.cs +++ b/src/Generator/Generators/Registrable/Utils/Utils.cs @@ -15,5 +15,10 @@ public static Declaration FindDescribedTemplate(Declaration declaration) } return null; } + + public static DetachmentOption FindDetachmentOption(Declaration declaration) + { + return (declaration.Namespace is Class) ? DetachmentOption.Off : DetachmentOption.On; + } } } From b653daf297310f36d2eb3a54b8b29347bbe300dc Mon Sep 17 00:00:00 2001 From: Deadlocklogic Date: Thu, 14 Dec 2023 11:06:51 +0200 Subject: [PATCH 03/13] Registrable: fix duplicated semi colon --- .../Generators/Registrable/Lua/Sol/LuaSolSources.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs index 24e88cafa..db569922e 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs @@ -810,17 +810,13 @@ public virtual bool GenerateVariableDecl(Variable variable) // TODO: check for typemaps!!! if (isDetach != DetachmentOption.Off) { - Write($"{variableBindingContext}[{variableNameQuoted}] = ::sol::var({variableContextualName});"); + WriteLine($"{variableBindingContext}[{variableNameQuoted}] = ::sol::var({variableContextualName});"); } else { WriteLine(","); Write($"{variableNameQuoted}, ::sol::var({variableContextualName})"); } - if (isDetach != DetachmentOption.Off) - { - WriteLine(";"); - } } return true; From 736531bd0b9781a856a0ee53156b1ad73313896c Mon Sep 17 00:00:00 2001 From: Deadlocklogic Date: Thu, 14 Dec 2023 12:41:33 +0200 Subject: [PATCH 04/13] Registrable: add support for constructor --- .../Registrable/Lua/Sol/LuaSolSources.cs | 115 ++++++++++++++++-- 1 file changed, 106 insertions(+), 9 deletions(-) diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs index db569922e..6a907b519 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs @@ -519,6 +519,7 @@ public virtual void GenerateClassDeclDeclarationList(Class @class, DetachmentOpt { if (detachment == DetachmentOption.Off) { + GenerateConstructors(@class, @class.Constructors); GenerateClassDeclFunctions(@class); GenerateClassDeclVariables(@class); } @@ -834,11 +835,79 @@ public override bool VisitVariableDecl(Variable variable) #endregion + #region Constructor + + public virtual bool NeedExpansionForConstructors(Class @class, IEnumerable constructors) + { + return false; + } + + public virtual void GenerateConstructors(Class @class, IEnumerable constructors) + { + var isDetach = GenerationContext.PeekIsDetach(); + + List filteredConstructors = constructors.Where((method) => CanGenerateConstructor(method)).ToList(); + if (filteredConstructors.Any()) + { + Method constructor = filteredConstructors.First(); + string constructorBindingContext = NamingStrategy.GetBindingContext(constructor, GenerationContext); + string constructorContextualName = NamingStrategy.GetContextualName(constructor, GenerationContext, FQNOption.IgnoreNone); + + if (isDetach == DetachmentOption.Forced || isDetach == Utils.FindDetachmentOption(constructor)) + { + + if (isDetach != DetachmentOption.Off) + { + Write($"{constructorBindingContext}[\"new\"] = "); + } + else + { + WriteLine(","); + Write($"\"new\", "); + } + if (NeedExpansionForConstructors(@class, constructors)) + { + Write("::sol::factories("); + Indent(); + for (int i = 0; i < filteredConstructors.Count; i++) + { + if (i > 0) + { + Write(","); + } + NewLine(); + GenerateConstructor(@class, filteredConstructors[i], true); + } + Unindent(); + WriteLine(")"); + } + else + { + Write("::sol::constructors<"); + Indent(); + for (int i = 0; i < filteredConstructors.Count; i++) + { + if (i > 0) + { + Write(","); + } + NewLine(); + GenerateConstructor(@class, filteredConstructors[i], false); + } + Unindent(); + NewLine(); + Write(">()"); + } + if (isDetach != DetachmentOption.Off) + { + WriteLine(";"); + } + } + } + } + public virtual bool CanGenerateConstructor(Method method) { - // if not self:isNonTemplateAllowed(context) then - // return true - // end if (AlreadyVisited(method)) { return false; @@ -847,20 +916,48 @@ public virtual bool CanGenerateConstructor(Method method) { return false; } + else if (!NonTemplateAllowed) + { + return false; + } return method.IsGenerated; } - public virtual void GenerateConstructors(Class @class, IEnumerable constructors) + public virtual void GenerateConstructor(Class @class, Method constructor, bool doExpand) { - var isDetach = GenerationContext.PeekIsDetach(); - - if (isDetach == DetachmentOption.Forced) + if (doExpand) { - var filteredConstructors = constructors.Where((method) => CanGenerateConstructor(method)); - foreach (var constructor in constructors) + // TODO: Implement when ready + } + else + { + Write(NamingStrategy.GetCppContext(constructor, GenerationContext, FQNOption.IgnoreNone)); + Write("("); + var needsComma = false; + foreach (var parameter in constructor.Parameters) + { + if (needsComma) + { + Write(", "); + } + else + { + needsComma = true; + } + Write(parameter.Type.Visit(new CppTypePrinter(Context))); + } + if (constructor.IsVariadic) { + if (needsComma) + { + Write(", "); + } + Write("..."); } + Write(")"); } } + + #endregion } } From d87d95a0cf0796bd4f321e94bdc606978dedd3c4 Mon Sep 17 00:00:00 2001 From: Deadlocklogic Date: Thu, 14 Dec 2023 13:46:36 +0200 Subject: [PATCH 05/13] Registrable: add support for method --- .../Registrable/Lua/Sol/LuaSolSources.cs | 130 +++++++++++++++++- 1 file changed, 126 insertions(+), 4 deletions(-) diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs index 6a907b519..799adade2 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs @@ -520,6 +520,12 @@ public virtual void GenerateClassDeclDeclarationList(Class @class, DetachmentOpt if (detachment == DetachmentOption.Off) { GenerateConstructors(@class, @class.Constructors); + + var methods = @class.Methods.Where(method => !(method.IsConstructor || method.IsDestructor || method.IsOperator)); + var uniqueMethods = methods.GroupBy(m => m.Name); + foreach (var group in uniqueMethods) + GenerateMethods(@class, group.ToList()); + GenerateClassDeclFunctions(@class); GenerateClassDeclVariables(@class); } @@ -906,13 +912,13 @@ public virtual void GenerateConstructors(Class @class, IEnumerable const } } - public virtual bool CanGenerateConstructor(Method method) + public virtual bool CanGenerateConstructor(Method constructor) { - if (AlreadyVisited(method)) + if (AlreadyVisited(constructor)) { return false; } - else if (method.Access != AccessSpecifier.Public) + else if (constructor.Access != AccessSpecifier.Public) { return false; } @@ -920,7 +926,7 @@ public virtual bool CanGenerateConstructor(Method method) { return false; } - return method.IsGenerated; + return constructor.IsGenerated; } public virtual void GenerateConstructor(Class @class, Method constructor, bool doExpand) @@ -959,5 +965,121 @@ public virtual void GenerateConstructor(Class @class, Method constructor, bool d } #endregion + + #region Method + + public virtual bool NeedExpansionForMethods(Class @class, IEnumerable methods) + { + return false; + } + + public virtual void GenerateMethods(Class @class, IEnumerable methods) + { + var isDetach = GenerationContext.PeekIsDetach(); + + List filteredMethods = methods.Where((method) => CanGenerateMethod(method)).ToList(); + if (filteredMethods.Any()) + { + Method method = filteredMethods.First(); + string methodName = method.Name; + string methodNameQuoted = $"\"{methodName}\""; + string methodBindingContext = NamingStrategy.GetBindingContext(method, GenerationContext); + string methodContextualName = NamingStrategy.GetContextualName(method, GenerationContext, FQNOption.IgnoreNone); + + if (isDetach == DetachmentOption.Forced || isDetach == Utils.FindDetachmentOption(method)) + { + + if (isDetach != DetachmentOption.Off) + { + Write($"{methodBindingContext}[{methodNameQuoted}] = "); + } + else + { + WriteLine(","); + Write($"{methodNameQuoted}, "); + } + if (filteredMethods.Count == 1) + { + GenerateMethod(@class, filteredMethods.First()); + } + else + { + Write("::sol::overload("); + Indent(); + for (int i = 0; i < filteredMethods.Count; i++) + { + if (i > 0) + { + Write(","); + } + NewLine(); + GenerateMethod(@class, filteredMethods[i]); + } + Unindent(); + NewLine(); + Write(")"); + } + if (isDetach != DetachmentOption.Off) + { + WriteLine(";"); + } + } + } + } + + public virtual bool CanGenerateMethod(Method method) + { + if (AlreadyVisited(method)) + { + return false; + } + else if (method.Access != AccessSpecifier.Public) + { + return false; + } + else if (!NonTemplateAllowed) + { + return false; + } + return method.IsGenerated; + } + + public virtual void GenerateMethod(Class @class, Method method) + { + { + Write("static_cast<"); + Write(method.ReturnType.Visit(new CppTypePrinter(Context))); + Write("("); + Write("*)"); + Write("("); + var needsComma = false; + foreach (var parameter in method.Parameters) + { + if (needsComma) + { + Write(", "); + } + else + { + needsComma = true; + } + Write(parameter.Type.Visit(new CppTypePrinter(Context))); + } + if (method.IsVariadic) + { + if (needsComma) + { + Write(", "); + } + Write("..."); + } + Write(")"); + Write(">(&"); + Write(NamingStrategy.GetContextualName(method, GenerationContext, FQNOption.IgnoreNone)); + Write(")"); + } + } + + #endregion } } From 94da6bee97352a66cc0c69ed6b168db7b0a4016b Mon Sep 17 00:00:00 2001 From: Deadlocklogic Date: Thu, 14 Dec 2023 14:09:53 +0200 Subject: [PATCH 06/13] Registrable: add support for function --- .../Registrable/Lua/Sol/LuaSolSources.cs | 138 +++++++++++++++++- 1 file changed, 135 insertions(+), 3 deletions(-) diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs index 799adade2..ff86ffa53 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs @@ -111,6 +111,13 @@ public virtual void GenerateTranslationUnitRegistrationFunctionBody(TranslationU { variable.Visit(this); } + + var methods = translationUnit.Functions.Where(method => !(method.IsOperator)); + var overloads = methods.GroupBy(m => m.Name); + foreach (var overload in overloads) + { + GenerateFunctions(translationUnit, overload.ToList()); + } }); } @@ -191,6 +198,13 @@ public virtual void GenerateNamespaceDeclarationList(Namespace @namespace, Detac { GenerateNamespaceFunctions(@namespace); GenerateNamespaceVariables(@namespace); + + var methods = @namespace.Functions.Where(method => !(method.IsOperator)); + var overloads = methods.GroupBy(m => m.Name); + foreach (var overload in overloads) + { + GenerateFunctions(@namespace, overload.ToList()); + } }); } @@ -522,9 +536,11 @@ public virtual void GenerateClassDeclDeclarationList(Class @class, DetachmentOpt GenerateConstructors(@class, @class.Constructors); var methods = @class.Methods.Where(method => !(method.IsConstructor || method.IsDestructor || method.IsOperator)); - var uniqueMethods = methods.GroupBy(m => m.Name); - foreach (var group in uniqueMethods) - GenerateMethods(@class, group.ToList()); + var overloads = methods.GroupBy(m => m.Name); + foreach (var overload in overloads) + { + GenerateMethods(@class, overload.ToList()); + } GenerateClassDeclFunctions(@class); GenerateClassDeclVariables(@class); @@ -966,6 +982,122 @@ public virtual void GenerateConstructor(Class @class, Method constructor, bool d #endregion + #region Function + + public virtual bool NeedExpansionForFunctions(Declaration declaration, IEnumerable functions) + { + return false; + } + + public virtual void GenerateFunctions(Declaration declaration, IEnumerable functions) + { + var isDetach = GenerationContext.PeekIsDetach(); + + List filteredFunctions = functions.Where((function) => CanGenerateFunction(function)).ToList(); + if (filteredFunctions.Any()) + { + Function function = filteredFunctions.First(); + string functionName = function.Name; + string functionNameQuoted = $"\"{functionName}\""; + string functionBindingContext = NamingStrategy.GetBindingContext(function, GenerationContext); + string functionContextualName = NamingStrategy.GetContextualName(function, GenerationContext, FQNOption.IgnoreNone); + + if (isDetach == DetachmentOption.Forced || isDetach == Utils.FindDetachmentOption(function)) + { + + if (isDetach != DetachmentOption.Off) + { + Write($"{functionBindingContext}[{functionNameQuoted}] = "); + } + else + { + WriteLine(","); + Write($"{functionNameQuoted}, "); + } + if (filteredFunctions.Count == 1) + { + GenerateFunction(declaration, filteredFunctions.First()); + } + else + { + Write("::sol::overload("); + Indent(); + for (int i = 0; i < filteredFunctions.Count; i++) + { + if (i > 0) + { + Write(","); + } + NewLine(); + GenerateFunction(declaration, filteredFunctions[i]); + } + Unindent(); + NewLine(); + Write(")"); + } + if (isDetach != DetachmentOption.Off) + { + WriteLine(";"); + } + } + } + } + + public virtual bool CanGenerateFunction(Function function) + { + if (AlreadyVisited(function)) + { + return false; + } + else if (function.Access != AccessSpecifier.Public) + { + return false; + } + else if (!NonTemplateAllowed) + { + return false; + } + return function.IsGenerated; + } + + public virtual void GenerateFunction(Declaration declaration, Function function) + { + { + Write("static_cast<"); + Write(function.ReturnType.Visit(new CppTypePrinter(Context))); + Write("("); + Write("*)"); + Write("("); + var needsComma = false; + foreach (var parameter in function.Parameters) + { + if (needsComma) + { + Write(", "); + } + else + { + needsComma = true; + } + Write(parameter.Type.Visit(new CppTypePrinter(Context))); + } + if (function.IsVariadic) + { + if (needsComma) + { + Write(", "); + } + Write("..."); + } + Write(")"); + Write(">(&"); + Write(NamingStrategy.GetContextualName(function, GenerationContext, FQNOption.IgnoreNone)); + Write(")"); + } + } + + #endregion + #region Method public virtual bool NeedExpansionForMethods(Class @class, IEnumerable methods) From 97110fd21fce5f5ccf700dfbfeb29daf94983547 Mon Sep 17 00:00:00 2001 From: Deadlocklogic Date: Thu, 14 Dec 2023 14:58:22 +0200 Subject: [PATCH 07/13] Registrable: fix lua artifacts --- .../Registrable/Lua/Sol/LuaSolSources.cs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs index ff86ffa53..661905db6 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs @@ -261,9 +261,6 @@ public virtual void GenerateNamespace(Namespace @namespace) public virtual bool CanGenerateNamespace(Namespace @namespace) { - // if not self:isNonTemplateAllowed(context) then - // return true - // end if (AlreadyVisited(@namespace)) { return false; @@ -272,6 +269,10 @@ public virtual bool CanGenerateNamespace(Namespace @namespace) { return false; } + else if (!NonTemplateAllowed) + { + return false; + } return @namespace.IsGenerated; } @@ -466,9 +467,6 @@ public virtual void GenerateEnumDecl(Enumeration enumeration) public virtual bool CanGenerateEnumDecl(Enumeration enumeration) { - // if not self:isNonTemplateAllowed(context) then - // return true - // end if (AlreadyVisited(enumeration)) { return false; @@ -477,6 +475,10 @@ public virtual bool CanGenerateEnumDecl(Enumeration enumeration) { return false; } + else if (!NonTemplateAllowed) + { + return false; + } return enumeration.IsGenerated; } From 9fb03a0a07b489d366ba829fd6981899b96eb24f Mon Sep 17 00:00:00 2001 From: Deadlocklogic Date: Thu, 14 Dec 2023 18:37:13 +0200 Subject: [PATCH 08/13] Registrable: cleanup + improvements --- .../Registrable/Lua/Sol/LuaSolGenerator.cs | 1 - .../Lua/Sol/LuaSolGeneratorOptions.cs | 12 +++ .../Registrable/Lua/Sol/LuaSolHeaders.cs | 87 ++-------------- .../Registrable/Lua/Sol/LuaSolSources.cs | 73 +++++++++++++- .../RegistrableGeneratorOptions.cs | 98 +++++++++++++------ .../Registrable/RegistrableNamingStrategy.cs | 24 ++--- 6 files changed, 171 insertions(+), 124 deletions(-) diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs index db7766ad0..596a4c4b1 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs @@ -3,7 +3,6 @@ namespace CppSharp.Generators.Registrable.Lua.Sol { - public class LuaSolGenerator : Generator { public const string Id = "Lua::Sol"; diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs index 158cb47bb..bf5169eb3 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs @@ -8,5 +8,17 @@ public LuaSolGeneratorOptions(LuaSolGenerator generator) : base() { NamingStrategy = new LuaSolNamingStrategy(generator); } + + public override string DefaultRootContextType => "::sol::state_view&"; + + public override string DefaultRootContextName => "state"; + + public override string DefaultTemplateContextDefaultType => "::sol::table"; + + public override string DefaultTemplateContextDefaultValue => "::sol::nil"; + + public override string DefaultCmakeVariableHeader => "LUA_SOL_BINDINGS_HEADER"; + + public override string DefaultCmakeVariableSource => "LUA_SOL_BINDINGS_SOURCE"; } } diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs index 78599525f..971a6fd51 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs @@ -12,6 +12,8 @@ public LuaSolHeaders(LuaSolGenerator generator, IEnumerable uni public override string FileExtension => "h"; + protected override bool TemplateAllowed { get { return true; } } + public override void Process() { GenerateFilePreamble(CommentKind.BCPL); @@ -20,32 +22,18 @@ public override void Process() WriteLine("#pragma once"); PopBlock(NewLineKind.BeforeNextBlock); - //NewLine(); - //PushBlock(BlockKind.Includes); - //GenerateIncludes(); - //PopBlock(NewLineKind.BeforeNextBlock); - TranslationUnit.Visit(this); - - //PushBlock(BlockKind.Footer); - //PopBlock(); - - //PushBlock(BlockKind.Class); - //PopBlock(NewLineKind.IfNotEmpty); - - //RegistrableGeneratorContext mycontext = new RegistrableGeneratorContext(); - //string a = (string)mycontext[new InfoEntry("")].Pop(); } #region TranslationUnit - public virtual void GenerateTranslationUnitNamespaceBegin(TranslationUnit translationUnit) + public override void GenerateTranslationUnitNamespaceBegin(TranslationUnit translationUnit) { PushBlock(BlockKind.Namespace); WriteLine($"namespace {TranslationUnit.Module.OutputNamespace} {{"); } - public virtual void GenerateTranslationUnitNamespaceEnd(TranslationUnit translationUnit) + public override void GenerateTranslationUnitNamespaceEnd(TranslationUnit translationUnit) { WriteLine($"}} // namespace {TranslationUnit.Module.OutputNamespace}"); PopBlock(); @@ -58,14 +46,14 @@ public virtual void GenerateTranslationUnitRegistrationFunctionDeclaration(Trans NewLine(); } - public virtual void GenerateTranslationUnit(TranslationUnit translationUnit) + public override void GenerateTranslationUnit(TranslationUnit translationUnit) { GenerateTranslationUnitNamespaceBegin(translationUnit); GenerateTranslationUnitRegistrationFunctionDeclaration(translationUnit); GenerateTranslationUnitNamespaceEnd(translationUnit); } - public virtual bool CanGenerateTranslationUnit(TranslationUnit unit) + public override bool CanGenerateTranslationUnit(TranslationUnit unit) { if (AlreadyVisited(unit)) { @@ -88,8 +76,6 @@ public override bool VisitTranslationUnit(TranslationUnit unit) #endregion - // - public virtual void GenerateMain() { VisitNamespace(TranslationUnit); @@ -97,67 +83,10 @@ public virtual void GenerateMain() public virtual void GenerateIncludes() { - foreach (var include in Generator.GeneratorOptions.CommonIncludes) - { - WriteLineIndent(include.ToString()); - } - } - - //public override bool VisitNamespace(Namespace @namespace) - //{ - // base.VisitNamespace(@namespace); - // return true; - //} - - public override bool VisitMethodDecl(Method method) - { - return true; - } - - public override bool VisitFunctionDecl(Function function) - { - //if (FunctionIsTemplate(function)) - //{ - // Console.WriteLine("test"); - //} - return true; - } - - public override bool VisitClassTemplateDecl(ClassTemplate template) - { - return true; - } - - public override bool VisitVariableDecl(Variable variable) - { - return true; - } - - public override bool VisitTypeAliasTemplateDecl(TypeAliasTemplate typeAliasTemplate) - { - return true; - } - - public override bool VisitTypedefNameDecl(TypedefNameDecl typedef) - { - return true; - } - - public override bool VisitFunctionTemplateDecl(FunctionTemplate template) - { - return true; - } - - public static bool FunctionIsTemplate(Function function) - { - foreach (var template in function.Namespace.Templates) + if (Generator.GeneratorOptions.BaseInclude != null) { - if (template.TemplatedDecl == function) - { - return true; - } + WriteLineIndent(Generator.GeneratorOptions.BaseInclude.ToString()); } - return false; } } } diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs index 661905db6..03f965e7e 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs @@ -118,6 +118,11 @@ public virtual void GenerateTranslationUnitRegistrationFunctionBody(TranslationU { GenerateFunctions(translationUnit, overload.ToList()); } + + foreach (var typedef in translationUnit.Typedefs) + { + typedef.Visit(this); + } }); } @@ -205,6 +210,11 @@ public virtual void GenerateNamespaceDeclarationList(Namespace @namespace, Detac { GenerateFunctions(@namespace, overload.ToList()); } + + foreach (var typedef in @namespace.Typedefs) + { + typedef.Visit(this); + } }); } @@ -235,7 +245,7 @@ public virtual void GenerateNamespaceVariables(Namespace @namespace) public virtual void GenerateNamespaceEnd(Namespace @namespace) { - GenerateNamespaceDeclarationList(@namespace, DetachmentOption.On); + //GenerateNamespaceDeclarationList(@namespace, DetachmentOption.On); } public virtual void GenerateNamespaceGlobalStateRegistration(Namespace @namespace) @@ -1215,5 +1225,66 @@ public virtual void GenerateMethod(Class @class, Method method) } #endregion + + #region Typedef + + public virtual bool CanGenerateTypedefNameDecl(TypedefNameDecl typedef) + { + if (AlreadyVisited(typedef)) + { + return false; + } + else if (typedef.Access != AccessSpecifier.Public) + { + return false; + } + else if (!NonTemplateAllowed) + { + return false; + } + return typedef.IsGenerated; + } + + public virtual void GenerateTypedefNameDecl(TypedefNameDecl typedef) + { + var type = typedef.Type; + if (type is TemplateSpecializationType templateSpecializationType) + { + string typedefName = typedef.Name; + string typedefNameQuoted = $"\"{typedefName}\""; + string typedefRegistrationFunctionName = NamingStrategy.GetFullyQualifiedName(templateSpecializationType.GetClassTemplateSpecialization(), new FQNOption() + { + IgnoreTemplateTypenameKeyword = true + }); + string typedefBindingContext = NamingStrategy.GetBindingContext(typedef, GenerationContext); + string typedefRootContextName = NamingStrategy.GetRootContextName(GenerationContext); + + WriteLine($"global{typedefRegistrationFunctionName}{{}}({typedefRootContextName}, {typedefBindingContext}, {typedefNameQuoted}); /* directly */"); + } + } + + public override bool VisitTypedefNameDecl(TypedefNameDecl typedef) + { + if (!CanGenerateTypedefNameDecl(typedef)) + { + return false; + } + + GenerateTypedefNameDecl(typedef); + + return true; + } + + public override bool VisitTypedefDecl(TypedefDecl typedef) + { + return VisitTypedefNameDecl(typedef); + } + + public override bool VisitTypeAliasDecl(TypeAlias typeAlias) + { + return VisitTypedefNameDecl(typeAlias); + } + + #endregion } } diff --git a/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs b/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs index 7e7e82d13..83650e65d 100644 --- a/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs +++ b/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs @@ -1,50 +1,86 @@ using CppSharp.Generators.C; -using System.Collections.Generic; namespace CppSharp.Generators.Registrable { + public enum ImportedClassTemplateMode + { + Direct, + Indirect, + Import + } + public abstract class RegistrableGeneratorOptions { public delegate string Delegate(string name); protected Generator generator; - public virtual ISet CommonIncludes { get; } public virtual string OutputSubDir { get; } + public virtual string RootContextType { get; } + public virtual string RootContextName { get; } + public virtual string RegisterFunctionName { get; } + public virtual CInclude? BaseInclude { get; } public Delegate BindingIdNamePredicate { get; } public Delegate BindingIdValuePredicate { get; } public Delegate BindingNamePredicate { get; } + public string TemplateTypenameState { get; } + public string TemplateTypenameContext { get; } + public string TemplateIdentifierState { get; } + public string TemplateIdentifierContext { get; } + public string TemplateContextDefaultType { get; } + public string TemplateContextDefaultValue { get; } + public ImportedClassTemplateMode ImportedTemplateMode { get; } + public string CppValidatorFileName { get; } + public string CmakeVariableHeader { get; } + public string CmakeVariableSource { get; } + public string EqualityFunctionTemplateFullyQualifiedName { get; } + public string StaticCastFunctionTemplateFullyQualifiedName { get; } + public string DynamicCastFunctionTemplateFullyQualifiedName { get; } - public RegistrableGeneratorOptions() - { - CommonIncludes = new HashSet(); - OutputSubDir = null; - BindingIdNamePredicate = DefaultBindingIdNamePredicate(); - BindingIdValuePredicate = DefaultBindingIdValuePredicate(); - BindingNamePredicate = DefaultBindingNamePredicate(); - } + public virtual string DefaultOutputSubdir => ""; + public abstract string DefaultRootContextType { get; } + public abstract string DefaultRootContextName { get; } + public virtual string DefaultRegisterFunctionName => "register_"; + public virtual CInclude? DefaultBaseInclude => null; + public virtual Delegate DefaultBindingIdNamePredicate => (string name) => $"_cppbind_id_{name}"; + public virtual Delegate DefaultBindingIdValuePredicate => (string name) => $"typeid({name}).name()"; + public virtual Delegate DefaultBindingNamePredicate => (string name) => $"_cppbind_{name}"; + public virtual string DefaultTemplateTypenameState => "CppBindState"; + public virtual string DefaultTemplateTypenameContext => "CppBindContext"; + public virtual string DefaultTemplateIdentifierState => "cpp_bind_state"; + public virtual string DefaultTemplateIdentifierContext => "cpp_bind_context"; + public abstract string DefaultTemplateContextDefaultType { get; } + public abstract string DefaultTemplateContextDefaultValue { get; } + public virtual ImportedClassTemplateMode DefaultImportedTemplateMode => ImportedClassTemplateMode.Indirect; + public virtual string DefaulCppValidatorFileName => "_cppbind_validator_"; + public virtual string DefaultCmakeVariableHeader => "BINDINGS_HEADER"; + public virtual string DefaultCmakeVariableSource => "BINDINGS_SOURCE"; + public virtual string DefaultEqualityFunctionTemplateFullyQualifiedName => null; + public virtual string DefaultStaticCastFunctionTemplateFullyQualifiedName => null; + public virtual string DefaultDynamicCastFunctionTemplateFullyQualifiedName => null; - public virtual Delegate DefaultBindingIdNamePredicate() - { - return (string name) => - { - return $"_cppbind_id_{name}"; - }; - } - - public virtual Delegate DefaultBindingIdValuePredicate() - { - return (string name) => - { - return $"typeid({name}).name()"; - }; - } - - public virtual Delegate DefaultBindingNamePredicate() + public RegistrableGeneratorOptions() { - return (string name) => - { - return $"_cppbind_{name}"; - }; + OutputSubDir = DefaultOutputSubdir; + RootContextType = DefaultRootContextType; + RootContextName = DefaultRootContextName; + RegisterFunctionName = DefaultRegisterFunctionName; + BaseInclude = DefaultBaseInclude; + BindingIdNamePredicate = DefaultBindingIdNamePredicate; + BindingIdValuePredicate = DefaultBindingIdValuePredicate; + BindingNamePredicate = DefaultBindingNamePredicate; + TemplateTypenameState = DefaultTemplateTypenameState; + TemplateTypenameContext = DefaultTemplateTypenameContext; + TemplateIdentifierState = DefaultTemplateIdentifierState; + TemplateIdentifierContext = DefaultTemplateIdentifierContext; + TemplateContextDefaultType = DefaultTemplateContextDefaultType; + TemplateContextDefaultValue = DefaultTemplateContextDefaultValue; + ImportedTemplateMode = DefaultImportedTemplateMode; + CppValidatorFileName = DefaulCppValidatorFileName; + CmakeVariableHeader = DefaultCmakeVariableHeader; + CmakeVariableSource = DefaultCmakeVariableSource; + EqualityFunctionTemplateFullyQualifiedName = DefaultEqualityFunctionTemplateFullyQualifiedName; + StaticCastFunctionTemplateFullyQualifiedName = DefaultStaticCastFunctionTemplateFullyQualifiedName; + DynamicCastFunctionTemplateFullyQualifiedName = DefaultDynamicCastFunctionTemplateFullyQualifiedName; } } } diff --git a/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs b/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs index fe7a4537e..3faeca9d9 100644 --- a/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs +++ b/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs @@ -22,7 +22,7 @@ public bool IsNestedTemplate(Declaration declaration) while (true) { currentDeclaration = currentDeclaration.OriginalNamespace; - if (currentDeclaration != null || currentDeclaration is TranslationUnit) + if (currentDeclaration == null || currentDeclaration is TranslationUnit) { break; } @@ -122,17 +122,17 @@ public virtual string PrintClassTemplateParameter(Declaration declaration, Templ return builder.ToString(); } - public virtual string PrintClassTemplateParameters(ClassTemplate classTemplate, bool includeEnclosingBrackets, TemplateParameterOption option) + public virtual string PrintClassTemplateParameters(List parameters, bool includeEnclosingBrackets, TemplateParameterOption option) { var builder = new StringBuilder(); builder.Append('<'); - for (int i = 0; i < classTemplate.Parameters.Count; i++) + for (int i = 0; i < parameters.Count; i++) { if (i > 0) { builder.Append(", "); } - builder.Append(PrintClassTemplateParameter(classTemplate.Parameters[i], option)); + builder.Append(PrintClassTemplateParameter(parameters[i], option)); } builder.Append('>'); return builder.ToString(); @@ -147,17 +147,17 @@ public virtual string PrintClassTemplateSpecializationArgument(TemplateArgument return templateArgument.Type.Type.Visit(new CppTypePrinter(Generator.Context)); } - public virtual string PrintClassTemplateSpecializationArguments(ClassTemplateSpecialization classTemplateSpecialization, bool includeEnclosingBrackets) + public virtual string PrintClassTemplateSpecializationArguments(List arguments, bool includeEnclosingBrackets) { var builder = new StringBuilder(); builder.Append('<'); - for (int i = 0; i < classTemplateSpecialization.Arguments.Count; i++) + for (int i = 0; i < arguments.Count; i++) { if (i > 0) { builder.Append(", "); } - builder.Append(PrintClassTemplateSpecializationArgument(classTemplateSpecialization.Arguments[i])); + builder.Append(PrintClassTemplateSpecializationArgument(arguments[i])); } builder.Append('>'); return builder.ToString(); @@ -177,7 +177,7 @@ public virtual string GetQualifiedName(Declaration declaration, FQNOption option { if (!option.IgnoreTemplateParameters) { - name = ($"{name}{PrintClassTemplateSpecializationArguments(specialization, true)}"); + name = ($"{name}{PrintClassTemplateSpecializationArguments(specialization.Arguments, true)}"); } } else @@ -190,7 +190,7 @@ public virtual string GetQualifiedName(Declaration declaration, FQNOption option { if (!option.IgnoreTemplateParameters) { - name = ($"{name}{PrintClassTemplateParameters(template, true, TemplateParameterOption.AsArgument)}"); + name = ($"{name}{PrintClassTemplateParameters(template.Parameters, true, TemplateParameterOption.AsArgument)}"); } } } @@ -235,7 +235,7 @@ public virtual string GetFullyQualifiedName(Declaration declaration, FQNOption o { needsTypename = true; } - currentName.Append(PrintClassTemplateSpecializationArguments(specialization, true)); + currentName.Append(PrintClassTemplateSpecializationArguments(specialization.Arguments, true)); } } else @@ -259,7 +259,7 @@ public virtual string GetFullyQualifiedName(Declaration declaration, FQNOption o { needsTypename = true; } - currentName.Append($"{name}{PrintClassTemplateParameters(template, true, TemplateParameterOption.AsArgument)}"); + currentName.Append($"{name}{PrintClassTemplateParameters(template.Parameters, true, TemplateParameterOption.AsArgument)}"); } } } @@ -371,7 +371,7 @@ public virtual string GetBindingContext(Declaration declaration, RegistrableGene var parentList = new List(); while (true) { - if (currentDeclaration != null || currentDeclaration is TranslationUnit) + if (currentDeclaration == null || currentDeclaration is TranslationUnit) { break; } From 45d4043342c57a93643643e58e256807b7580ca9 Mon Sep 17 00:00:00 2001 From: Deadlocklogic Date: Thu, 14 Dec 2023 18:42:26 +0200 Subject: [PATCH 09/13] Registrable: cleanup --- .../Registrable/Lua/Sol/LuaSolGeneratorOptions.cs | 2 +- .../Generators/Registrable/RegistrableGeneratorOptions.cs | 6 ++++-- .../Generators/Registrable/RegistrableNamingStrategy.cs | 3 +-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs index bf5169eb3..5eb17f8c7 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs @@ -4,7 +4,7 @@ public class LuaSolGeneratorOptions : RegistrableGeneratorOptions { public LuaSolNamingStrategy NamingStrategy; - public LuaSolGeneratorOptions(LuaSolGenerator generator) : base() + public LuaSolGeneratorOptions(LuaSolGenerator generator) : base(generator) { NamingStrategy = new LuaSolNamingStrategy(generator); } diff --git a/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs b/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs index 83650e65d..597b1fa0e 100644 --- a/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs +++ b/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs @@ -13,7 +13,8 @@ public abstract class RegistrableGeneratorOptions { public delegate string Delegate(string name); - protected Generator generator; + protected Generator Generator; + public virtual string OutputSubDir { get; } public virtual string RootContextType { get; } public virtual string RootContextName { get; } @@ -58,8 +59,9 @@ public abstract class RegistrableGeneratorOptions public virtual string DefaultStaticCastFunctionTemplateFullyQualifiedName => null; public virtual string DefaultDynamicCastFunctionTemplateFullyQualifiedName => null; - public RegistrableGeneratorOptions() + public RegistrableGeneratorOptions(Generator generator) { + Generator = generator; OutputSubDir = DefaultOutputSubdir; RootContextType = DefaultRootContextType; RootContextName = DefaultRootContextName; diff --git a/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs b/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs index 3faeca9d9..b23e46548 100644 --- a/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs +++ b/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs @@ -3,7 +3,6 @@ using CppSharp.Generators.Registrable.Lua.Sol; using System.Collections.Generic; using System.Text; -using System.Xml.Linq; namespace CppSharp.Generators.Registrable { @@ -386,7 +385,7 @@ public virtual string GetBindingContext(Declaration declaration, RegistrableGene } } - public string GetCppContext(Declaration entity, RegistrableGeneratorContext context, FQNOption option) + public virtual string GetCppContext(Declaration entity, RegistrableGeneratorContext context, FQNOption option) { if (context != null) { From 9ce5cc631f56f343912e6f238fdcc90c733cf474 Mon Sep 17 00:00:00 2001 From: Deadlocklogic Date: Fri, 15 Dec 2023 13:50:40 +0200 Subject: [PATCH 10/13] Registrable: generify the API + improvements --- .../Registrable/Lua/Sol/LuaSolGenerator.cs | 24 ++++++------- .../Lua/Sol/LuaSolGeneratorOptions.cs | 2 +- .../Registrable/Lua/Sol/LuaSolHeaders.cs | 15 ++------ .../Registrable/Lua/Sol/LuaSolSources.cs | 24 ++++++------- .../Registrable/RegistrableCodeGenerator.cs | 16 +++++++++ .../Registrable/RegistrableGenerator.cs | 34 +++++++++++++++++++ .../RegistrableGeneratorOptions.cs | 7 ++-- .../Registrable/RegistrableHeaders.cs | 13 +++++++ .../Registrable/RegistrableNamingStrategy.cs | 12 +++++++ .../Registrable/RegistrableSources.cs | 13 +++++++ 10 files changed, 116 insertions(+), 44 deletions(-) create mode 100644 src/Generator/Generators/Registrable/RegistrableCodeGenerator.cs create mode 100644 src/Generator/Generators/Registrable/RegistrableGenerator.cs create mode 100644 src/Generator/Generators/Registrable/RegistrableHeaders.cs create mode 100644 src/Generator/Generators/Registrable/RegistrableSources.cs diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs index 596a4c4b1..ff55e533e 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs @@ -3,32 +3,28 @@ namespace CppSharp.Generators.Registrable.Lua.Sol { - public class LuaSolGenerator : Generator + public class LuaSolGenerator : RegistrableGenerator { public const string Id = "Lua::Sol"; public static readonly GeneratorKind Kind = new(Id, "lua::sol", typeof(LuaSolGenerator), typeof(LuaSolTypePrinter), new[] { "lua::sol" }); - public LuaSolGeneratorOptions GeneratorOptions + public LuaSolGenerator(BindingContext context) : base(context) { - get; } - public LuaSolGenerator(BindingContext context) : base(context) + protected override LuaSolGeneratorOptions CreateOptions(RegistrableGenerator generator) { - GeneratorOptions = new LuaSolGeneratorOptions(this); + return new LuaSolGeneratorOptions(this); } - public override List Generate(IEnumerable units) + protected override LuaSolHeaders CreateHeader(RegistrableGenerator generator, IEnumerable units) { - var outputs = new List(); - - var header = new LuaSolHeaders(this, units); - outputs.Add(header); - - var source = new LuaSolSources(this, units); - outputs.Add(source); + return new LuaSolHeaders(this, units); + } - return outputs; + protected override LuaSolSources CreateSource(RegistrableGenerator generator, IEnumerable units) + { + return new LuaSolSources(this, units); } public override bool SetupPasses() => true; diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs index 5eb17f8c7..1948b7d1d 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGeneratorOptions.cs @@ -1,6 +1,6 @@ namespace CppSharp.Generators.Registrable.Lua.Sol { - public class LuaSolGeneratorOptions : RegistrableGeneratorOptions + public class LuaSolGeneratorOptions : RegistrableGeneratorOptions { public LuaSolNamingStrategy NamingStrategy; diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs index 971a6fd51..2c648652e 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs @@ -27,22 +27,11 @@ public override void Process() #region TranslationUnit - public override void GenerateTranslationUnitNamespaceBegin(TranslationUnit translationUnit) - { - PushBlock(BlockKind.Namespace); - WriteLine($"namespace {TranslationUnit.Module.OutputNamespace} {{"); - } - - public override void GenerateTranslationUnitNamespaceEnd(TranslationUnit translationUnit) - { - WriteLine($"}} // namespace {TranslationUnit.Module.OutputNamespace}"); - PopBlock(); - } - public virtual void GenerateTranslationUnitRegistrationFunctionDeclaration(TranslationUnit translationUnit) { NewLine(); - WriteLine(GetTranslationUnitRegistrationFunctionSignature(translationUnit)); + GenerateTranslationUnitRegistrationFunctionSignature(translationUnit); + WriteLine(";"); NewLine(); } diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs index 03f965e7e..1e8691d06 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs @@ -6,16 +6,14 @@ namespace CppSharp.Generators.Registrable.Lua.Sol { - public class LuaSolSources : CodeGenerator + public class LuaSolSources : RegistrableSources { - protected LuaSolGenerator Generator { get; } protected LuaSolGenerationContext GenerationContext { get; } protected LuaSolNamingStrategy NamingStrategy => Generator.GeneratorOptions.NamingStrategy; public LuaSolSources(LuaSolGenerator generator, IEnumerable units) - : base(generator.Context, units) + : base(generator, units) { - Generator = generator; GenerationContext = new LuaSolGenerationContext(); } @@ -72,13 +70,12 @@ public virtual void GenerateDeclarationContainerList(DeclarationContext declarat #region TranslationUnit - public virtual string GetTranslationUnitRegistrationFunctionSignature(TranslationUnit translationUnit) + public virtual void GenerateTranslationUnitRegistrationFunctionSignature(TranslationUnit translationUnit) { - StringBuilder builder = new StringBuilder(); - builder.Append("void "); - builder.Append(Generator.GeneratorOptions.NamingStrategy.GetRegistrationFunctionName(translationUnit)); - builder.Append("(::sol::state_view& state) {"); - return builder.ToString(); + var generatorOptions = Generator.GeneratorOptions; + Write("void "); + Write(generatorOptions.NamingStrategy.GetRegistrationFunctionName(translationUnit)); + Write($"({generatorOptions.RootContextType} {generatorOptions.RootContextName})"); } public virtual void GenerateTranslationUnitNamespaceBegin(TranslationUnit translationUnit) @@ -97,7 +94,8 @@ public virtual void GenerateTranslationUnitRegistrationFunctionBegin(Translation { PushBlock(BlockKind.Function); NewLine(); - WriteLine(GetTranslationUnitRegistrationFunctionSignature(translationUnit)); + GenerateTranslationUnitRegistrationFunctionSignature(translationUnit); + WriteLine(" {"); Indent(); } @@ -1194,7 +1192,7 @@ public virtual void GenerateMethod(Class @class, Method method) Write("static_cast<"); Write(method.ReturnType.Visit(new CppTypePrinter(Context))); Write("("); - Write("*)"); + Write($"{NamingStrategy.GetMembershipScopeName(method, GenerationContext)}*)"); Write("("); var needsComma = false; foreach (var parameter in method.Parameters) @@ -1259,7 +1257,7 @@ public virtual void GenerateTypedefNameDecl(TypedefNameDecl typedef) string typedefBindingContext = NamingStrategy.GetBindingContext(typedef, GenerationContext); string typedefRootContextName = NamingStrategy.GetRootContextName(GenerationContext); - WriteLine($"global{typedefRegistrationFunctionName}{{}}({typedefRootContextName}, {typedefBindingContext}, {typedefNameQuoted}); /* directly */"); + WriteLine($"//TODO: global{typedefRegistrationFunctionName}{{}}({typedefRootContextName}, {typedefBindingContext}, {typedefNameQuoted}); /* directly */"); } } diff --git a/src/Generator/Generators/Registrable/RegistrableCodeGenerator.cs b/src/Generator/Generators/Registrable/RegistrableCodeGenerator.cs new file mode 100644 index 000000000..b537d9fe7 --- /dev/null +++ b/src/Generator/Generators/Registrable/RegistrableCodeGenerator.cs @@ -0,0 +1,16 @@ +using CppSharp.AST; +using System.Collections.Generic; + +namespace CppSharp.Generators.Registrable +{ + public abstract class RegistrableCodeGenerator : CodeGenerator + where TGenerator : Generator + { + public TGenerator Generator { get; set; } + + public RegistrableCodeGenerator(TGenerator generator, IEnumerable units) : base(generator.Context, units) + { + Generator = generator; + } + } +} diff --git a/src/Generator/Generators/Registrable/RegistrableGenerator.cs b/src/Generator/Generators/Registrable/RegistrableGenerator.cs new file mode 100644 index 000000000..670e111cb --- /dev/null +++ b/src/Generator/Generators/Registrable/RegistrableGenerator.cs @@ -0,0 +1,34 @@ +using CppSharp.AST; +using System.Collections.Generic; + +namespace CppSharp.Generators.Registrable +{ + public abstract class RegistrableGenerator : Generator + where THeader : CodeGenerator + where TSource : CodeGenerator + { + public TOptions GeneratorOptions { get; } + + public RegistrableGenerator(BindingContext context) : base(context) + { + GeneratorOptions = CreateOptions(this); + } + + protected abstract TOptions CreateOptions(RegistrableGenerator generator); + + protected abstract THeader CreateHeader(RegistrableGenerator generator, IEnumerable units); + + protected abstract TSource CreateSource(RegistrableGenerator generator, IEnumerable units); + + public override List Generate(IEnumerable units) + { + return new List + { + CreateHeader(this, units), + CreateSource(this, units) + }; + } + + public override bool SetupPasses() => true; + } +} diff --git a/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs b/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs index 597b1fa0e..04dfb8927 100644 --- a/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs +++ b/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs @@ -9,11 +9,12 @@ public enum ImportedClassTemplateMode Import } - public abstract class RegistrableGeneratorOptions + public abstract class RegistrableGeneratorOptions + where TGenerator : Generator { public delegate string Delegate(string name); - protected Generator Generator; + public TGenerator Generator { get; set; } public virtual string OutputSubDir { get; } public virtual string RootContextType { get; } @@ -59,7 +60,7 @@ public abstract class RegistrableGeneratorOptions public virtual string DefaultStaticCastFunctionTemplateFullyQualifiedName => null; public virtual string DefaultDynamicCastFunctionTemplateFullyQualifiedName => null; - public RegistrableGeneratorOptions(Generator generator) + public RegistrableGeneratorOptions(TGenerator generator) { Generator = generator; OutputSubDir = DefaultOutputSubdir; diff --git a/src/Generator/Generators/Registrable/RegistrableHeaders.cs b/src/Generator/Generators/Registrable/RegistrableHeaders.cs new file mode 100644 index 000000000..7ee159fb4 --- /dev/null +++ b/src/Generator/Generators/Registrable/RegistrableHeaders.cs @@ -0,0 +1,13 @@ +using CppSharp.AST; +using System.Collections.Generic; + +namespace CppSharp.Generators.Registrable +{ + public abstract class RegistrableHeaders : RegistrableCodeGenerator + where TGenerator : Generator + { + public RegistrableHeaders(TGenerator generator, IEnumerable units) : base(generator, units) + { + } + } +} diff --git a/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs b/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs index b23e46548..037fea4eb 100644 --- a/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs +++ b/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs @@ -397,5 +397,17 @@ public virtual string GetCppContext(Declaration entity, RegistrableGeneratorCont } return GetFullyQualifiedName(entity.OriginalNamespace, option); } + + public virtual string GetMembershipScopeName(Function function, RegistrableGeneratorContext context) + { + if (function is Method method) + { + return GetCppContext(method, context, new FQNOption() + { + IgnoreTemplateTypenameKeyword = true + }) + "::"; + } + return ""; + } } } diff --git a/src/Generator/Generators/Registrable/RegistrableSources.cs b/src/Generator/Generators/Registrable/RegistrableSources.cs new file mode 100644 index 000000000..31c2811c0 --- /dev/null +++ b/src/Generator/Generators/Registrable/RegistrableSources.cs @@ -0,0 +1,13 @@ +using CppSharp.AST; +using System.Collections.Generic; + +namespace CppSharp.Generators.Registrable +{ + public abstract class RegistrableSources : RegistrableCodeGenerator + where TGenerator : Generator + { + public RegistrableSources(TGenerator generator, IEnumerable units) : base(generator, units) + { + } + } +} From 6360b77c7e117b2d2576ad586d15e2b71ae9efc2 Mon Sep 17 00:00:00 2001 From: Deadlocklogic Date: Sat, 16 Dec 2023 14:38:22 +0200 Subject: [PATCH 11/13] Registrable: add support for class template, imported class + improvements --- .../Registrable/Lua/Sol/LuaSolHeaders.cs | 1 + .../Registrable/Lua/Sol/LuaSolSources.cs | 795 +++++++++++++++++- .../RegistrableGeneratorContext.cs | 9 +- .../Registrable/RegistrableNamingStrategy.cs | 59 +- .../Generators/Registrable/Utils/Utils.cs | 117 ++- 5 files changed, 964 insertions(+), 17 deletions(-) diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs index 2c648652e..acc9fe919 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolHeaders.cs @@ -38,6 +38,7 @@ public virtual void GenerateTranslationUnitRegistrationFunctionDeclaration(Trans public override void GenerateTranslationUnit(TranslationUnit translationUnit) { GenerateTranslationUnitNamespaceBegin(translationUnit); + GenerateTranslationUnitRegistrationFunctionBody(translationUnit); GenerateTranslationUnitRegistrationFunctionDeclaration(translationUnit); GenerateTranslationUnitNamespaceEnd(translationUnit); } diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs index 1e8691d06..84a468376 100644 --- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs +++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs @@ -2,7 +2,6 @@ using CppSharp.Generators.C; using System.Collections.Generic; using System.Linq; -using System.Text; namespace CppSharp.Generators.Registrable.Lua.Sol { @@ -60,12 +59,121 @@ public virtual void GenerateDeclarationGlobalStateRegistration(Declaration decla public virtual void GenerateDeclarationContainerList(DeclarationContext declaration) { - List declarations = declaration.Declarations.Where(declaration => declaration is Namespace || declaration is Class || declaration is Enumeration).ToList(); - declarations.Sort((x, y) => x.LineNumberStart.CompareTo(y.LineNumberStart)); - foreach (var item in declarations) + List containerList = declaration.Declarations.Where(declaration => + { + if (declaration is Namespace || declaration is Enumeration) + { + return true; + } + else if (declaration is Class) + { + return Utils.FindDescribedTemplate(declaration) == null; + } + return false; + }).ToList(); + containerList.Sort((x, y) => x.LineNumberStart.CompareTo(y.LineNumberStart)); + foreach (var item in containerList) { item.Visit(this); }; + + if (NonTemplateAllowed) + { + List classTemplateList = declaration.Templates.Where(template => template is ClassTemplate).Cast().ToList(); + classTemplateList.Sort((x, y) => x.LineNumberStart.CompareTo(y.LineNumberStart)); + foreach (var classTemplate in classTemplateList) + { + if (Utils.IsDefaultTemplateParameterList(classTemplate.Parameters)) + { + Write(string.Format("{0}<>{{}}({1}", + NamingStrategy.GetClassTemplateName(classTemplate), + NamingStrategy.GetRootContextName(GenerationContext) + )); + if (classTemplate.OriginalName != classTemplate.Name) + { + Write(", "); + Write(NamingStrategy.GetRootContextName(GenerationContext)); + Write(", "); + Write(classTemplate.Name); + } + WriteLine(");"); + } + + foreach (var classTemplateSpecialization in classTemplate.Specializations) + { + if (classTemplateSpecialization is not ClassTemplatePartialSpecialization) + { + if (classTemplateSpecialization.SpecializationKind == TemplateSpecializationKind.ExplicitSpecialization) + { + Write(string.Format("{0}<{1}>{{}}({2}", + NamingStrategy.GetClassTemplateName(classTemplateSpecialization), + NamingStrategy.PrintClassTemplateSpecializationArguments(classTemplateSpecialization.Arguments, false), + NamingStrategy.GetRootContextName(GenerationContext) + )); + if (classTemplateSpecialization.OriginalName != classTemplateSpecialization.Name) + { + Write(", "); + Write(NamingStrategy.GetRootContextName(GenerationContext)); + Write(", "); + Write(classTemplateSpecialization.Name); + } + WriteLine(");"); + } + } + } + }; + } + } + + public virtual void GenerateDeclarationTemplateList(DeclarationContext declaration) + { + if (!TemplateAllowed) + { + return; + } + + List containerList = declaration.Declarations.Where(declaration => + { + if (declaration is Namespace || declaration is Enumeration) + { + return true; + } + else if (declaration is Class) + { + return Utils.FindDescribedTemplate(declaration) == null; + } + return false; + }).ToList(); + containerList.Sort((x, y) => x.LineNumberStart.CompareTo(y.LineNumberStart)); + foreach (var item in containerList) + { + if (item.Access == AccessSpecifier.Protected) + { + item.Visit(this); + } + else + { + GenerateDeclarationTemplateList((DeclarationContext)item); + } + }; + + List classTemplateList = declaration.Templates.Where(template => template is ClassTemplate).Cast().ToList(); + classTemplateList.Sort((x, y) => x.LineNumberStart.CompareTo(y.LineNumberStart)); + foreach (var classTemplate in classTemplateList) + { + classTemplate.Visit(this); + foreach (var classTemplateSpecialization in classTemplate.Specializations) + { + classTemplateSpecialization.Visit(this); + } + }; + + //List