From 8afc2b3e1e1348825ffaffcccf86e6ffeae0c19c Mon Sep 17 00:00:00 2001
From: Deadlocklogic <deadlocklogic@gmail.com>
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<CodeGenerator> Generate(IEnumerable<TranslationUnit> units)
+        {
+            var outputs = new List<CodeGenerator>();
+
+            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<TranslationUnit> 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<LuaSolGenerator>
+    {
+        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<TranslationUnit> 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<Declaration> 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<Enumeration.Item> 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<Enumeration.Item> 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<Method> 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<object>
+    {
+        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<DetachmentOption>(IsDetach);
+        }
+
+        public string PeekRootContextName(string defaultValue = default)
+        {
+            return Peek(RootContextName, defaultValue);
+        }
+
+        public void PushRootContextName(string item)
+        {
+            Push(RootContextName, item);
+        }
+
+        public string PopRootContextName()
+        {
+            return Pop<string>(RootContextName);
+        }
+
+        public string PeekBindingContext(string defaultValue = default)
+        {
+            return Peek(BindingContext, defaultValue);
+        }
+
+        public void PushBindingContext(string item)
+        {
+            Push(BindingContext, item);
+        }
+
+        public string PopBindingContext()
+        {
+            return Pop<string>(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>(CppContext);
+        }
+
+        public int PeekTemplateLevel(int defaultValue = default)
+        {
+            return Peek(TemplateLevel, defaultValue);
+        }
+
+        public void PushTemplateLevel(int item)
+        {
+            Push(TemplateLevel, item);
+        }
+
+        public int PopTemplateLevel()
+        {
+            return Pop<int>(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<CInclude> CommonIncludes { get; }
+        public virtual string OutputSubDir { get; }
+        public Delegate BindingIdNamePredicate { get; }
+        public Delegate BindingIdValuePredicate { get; }
+        public Delegate BindingNamePredicate { get; }
+
+        public RegistrableGeneratorOptions()
+        {
+            CommonIncludes = new HashSet<CInclude>();
+            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<T> 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<Declaration>();
+                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<InfoEntry>
+    {
+        public static readonly HashSet<InfoEntry> 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<T> : Dictionary<InfoEntry, T>
+    {
+        public InfoMap() : base()
+        {
+        }
+
+        public T1 Get<T1>(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<T> : InfoMap<Stack<T>>
+    {
+        public InfoMapStack() : base()
+        {
+        }
+
+        public T1 Peek<T1>(InfoEntry infoEntry, T1 defaultValue = default) where T1 : T
+        {
+            if (TryGetValue(infoEntry, out Stack<T> stack))
+            {
+                return (T1)stack.Peek();
+            }
+            return defaultValue;
+        }
+
+        public T1 Pop<T1>(InfoEntry infoEntry) where T1 : T
+        {
+            if (TryGetValue(infoEntry, out Stack<T> stack))
+            {
+                return (T1)stack.Pop();
+            }
+            throw new InvalidOperationException();
+        }
+
+        public void Push<T1>(InfoEntry infoEntry, T1 item) where T1 : T
+        {
+            if (!TryGetValue(infoEntry, out Stack<T> stack))
+            {
+                this[infoEntry] = stack = new Stack<T>();
+            }
+            stack.Push(item);
+        }
+
+        public bool TryPeek<T1>(InfoEntry infoEntry, [MaybeNullWhen(false)] out T1 result) where T1 : T
+        {
+            if (TryGetValue(infoEntry, out Stack<T> stack))
+            {
+                bool tempReturn = stack.TryPop(out T tempResult);
+                result = (T1)tempResult;
+                return tempReturn;
+            }
+            result = default;
+            return false;
+        }
+
+        public bool TryPop<T1>(InfoEntry infoEntry, [MaybeNullWhen(false)] out T1 result) where T1 : T
+        {
+            if (TryGetValue(infoEntry, out Stack<T> stack))
+            {
+                bool tempReturn = stack.TryPop(out T tempResult);
+                result = (T1)tempResult;
+                return tempReturn;
+            }
+            result = default;
+            return false;
+        }
+
+        public void Scoped<T1>(InfoEntry infoEntry, T1 item, Action action) where T1 : T
+        {
+            Push(infoEntry, item);
+            action();
+            Pop<T>(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 <deadlocklogic@gmail.com>
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<T1>(InfoEntry infoEntry, T1 defaultValue = default) where T1 : T
         {
             if (TryGetValue(infoEntry, out Stack<T> stack))
             {
-                return (T1)stack.Peek();
+                if (stack.Count > 0)
+                {
+                    return (T1)stack.Peek();
+                }
             }
             return defaultValue;
         }
@@ -61,7 +64,7 @@ public bool TryPop<T1>(InfoEntry infoEntry, [MaybeNullWhen(false)] out T1 result
             return false;
         }
 
-        public void Scoped<T1>(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 <deadlocklogic@gmail.com>
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 <deadlocklogic@gmail.com>
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<Method> constructors)
+        {
+            return false;
+        }
+
+        public virtual void GenerateConstructors(Class @class, IEnumerable<Method> constructors)
+        {
+            var isDetach = GenerationContext.PeekIsDetach();
+
+            List<Method> 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<Method> 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 <deadlocklogic@gmail.com>
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<Method> 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<Method> methods)
+        {
+            return false;
+        }
+
+        public virtual void GenerateMethods(Class @class, IEnumerable<Method> methods)
+        {
+            var isDetach = GenerationContext.PeekIsDetach();
+
+            List<Method> 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 <deadlocklogic@gmail.com>
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<Function> functions)
+        {
+            return false;
+        }
+
+        public virtual void GenerateFunctions(Declaration declaration, IEnumerable<Function> functions)
+        {
+            var isDetach = GenerationContext.PeekIsDetach();
+
+            List<Function> 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<Method> methods)

From 97110fd21fce5f5ccf700dfbfeb29daf94983547 Mon Sep 17 00:00:00 2001
From: Deadlocklogic <deadlocklogic@gmail.com>
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 <deadlocklogic@gmail.com>
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<TranslationUnit> 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<CInclude> 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<CInclude>();
-            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<Declaration> 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<TemplateArgument> 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<Declaration>();
                 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 <deadlocklogic@gmail.com>
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 <deadlocklogic@gmail.com>
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<LuaSolGeneratorOptions, LuaSolHeaders, LuaSolSources>
     {
         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<LuaSolGeneratorOptions, LuaSolHeaders, LuaSolSources> generator)
         {
-            GeneratorOptions = new LuaSolGeneratorOptions(this);
+            return new LuaSolGeneratorOptions(this);
         }
 
-        public override List<CodeGenerator> Generate(IEnumerable<TranslationUnit> units)
+        protected override LuaSolHeaders CreateHeader(RegistrableGenerator<LuaSolGeneratorOptions, LuaSolHeaders, LuaSolSources> generator, IEnumerable<TranslationUnit> units)
         {
-            var outputs = new List<CodeGenerator>();
-
-            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<LuaSolGeneratorOptions, LuaSolHeaders, LuaSolSources> generator, IEnumerable<TranslationUnit> 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<LuaSolGenerator>
     {
         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<LuaSolGenerator>
     {
-        protected LuaSolGenerator Generator { get; }
         protected LuaSolGenerationContext GenerationContext { get; }
         protected LuaSolNamingStrategy NamingStrategy => Generator.GeneratorOptions.NamingStrategy;
 
         public LuaSolSources(LuaSolGenerator generator, IEnumerable<TranslationUnit> 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<TGenerator> : CodeGenerator
+        where TGenerator : Generator
+    {
+        public TGenerator Generator { get; set; }
+
+        public RegistrableCodeGenerator(TGenerator generator, IEnumerable<TranslationUnit> 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<TOptions, THeader, TSource> : 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<TOptions, THeader, TSource> generator);
+
+        protected abstract THeader CreateHeader(RegistrableGenerator<TOptions, THeader, TSource> generator, IEnumerable<TranslationUnit> units);
+
+        protected abstract TSource CreateSource(RegistrableGenerator<TOptions, THeader, TSource> generator, IEnumerable<TranslationUnit> units);
+
+        public override List<CodeGenerator> Generate(IEnumerable<TranslationUnit> units)
+        {
+            return new List<CodeGenerator>
+            {
+                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<TGenerator>
+        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<TGenerator> : RegistrableCodeGenerator<TGenerator>
+        where TGenerator : Generator
+    {
+        public RegistrableHeaders(TGenerator generator, IEnumerable<TranslationUnit> 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<TGenerator> : RegistrableCodeGenerator<TGenerator>
+        where TGenerator : Generator
+    {
+        public RegistrableSources(TGenerator generator, IEnumerable<TranslationUnit> units) : base(generator, units)
+        {
+        }
+    }
+}

From 6360b77c7e117b2d2576ad586d15e2b71ae9efc2 Mon Sep 17 00:00:00 2001
From: Deadlocklogic <deadlocklogic@gmail.com>
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<Declaration> 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<Declaration> 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<ClassTemplate> classTemplateList = declaration.Templates.Where(template => template is ClassTemplate).Cast<ClassTemplate>().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<Declaration> 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<ClassTemplate> classTemplateList = declaration.Templates.Where(template => template is ClassTemplate).Cast<ClassTemplate>().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<Template> functionTemplateList = declaration.Templates.Where(template => template is FunctionTemplate).ToList();
+            //functionTemplateList.Sort((x, y) => x.LineNumberStart.CompareTo(y.LineNumberStart));
+            //foreach (var item in functionTemplateList)
+            //{
+            //    item.Visit(this);
+            //};
         }
 
         #region TranslationUnit
@@ -101,6 +209,7 @@ public virtual void GenerateTranslationUnitRegistrationFunctionBegin(Translation
 
         public virtual void GenerateTranslationUnitRegistrationFunctionBody(TranslationUnit translationUnit)
         {
+            GenerateDeclarationTemplateList(translationUnit);
             GenerateDeclarationContainerList(translationUnit);
 
             GenerationContext.Scoped(RegistrableGeneratorContext.IsDetach, DetachmentOption.On, () =>
@@ -635,6 +744,10 @@ public virtual bool CanGenerateClassDecl(Class @class)
             {
                 return false;
             }
+            else if (@class.IsIncomplete)
+            {
+                return false;
+            }
             else if (!NonTemplateAllowed)
             {
                 return false;
@@ -648,12 +761,24 @@ public virtual bool CanGenerateClassDecl(Class @class)
 
         public override bool VisitClassDecl(Class @class)
         {
-            if (!CanGenerateClassDecl(@class))
+            if (IsClassDeclImported(@class))
             {
-                return false;
+                if (!CanGenerateClassDeclImported(@class))
+                {
+                    return false;
+                }
+
+                GenerateClassDeclImported(@class);
             }
+            else
+            {
+                if (!CanGenerateClassDecl(@class))
+                {
+                    return false;
+                }
 
-            GenerateClassDecl(@class);
+                GenerateClassDecl(@class);
+            }
 
             return true;
         }
@@ -952,6 +1077,10 @@ public virtual bool CanGenerateConstructor(Method constructor)
             {
                 return false;
             }
+            else if (Utils.FindDescribedTemplate(constructor) != null)
+            {
+                return false;
+            }
             return constructor.IsGenerated;
         }
 
@@ -1067,11 +1196,16 @@ public virtual bool CanGenerateFunction(Function function)
             {
                 return false;
             }
+            else if (Utils.FindDescribedTemplate(function) != null)
+            {
+                return false;
+            }
             return function.IsGenerated;
         }
 
         public virtual void GenerateFunction(Declaration declaration, Function function)
         {
+            if (Utils.HasPossibleTemplateOverload(function))
             {
                 Write("static_cast<");
                 Write(function.ReturnType.Visit(new CppTypePrinter(Context)));
@@ -1104,6 +1238,43 @@ public virtual void GenerateFunction(Declaration declaration, Function function)
                 Write(NamingStrategy.GetContextualName(function, GenerationContext, FQNOption.IgnoreNone));
                 Write(")");
             }
+            else if (Utils.HasPossibleOverload(function))
+            {
+                Write("::sol::resolve<");
+                Write(function.ReturnType.Visit(new CppTypePrinter(Context)));
+                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(")");
+            }
+            else
+            {
+                Write(string.Format("&{0}",
+                    NamingStrategy.GetContextualName(function, GenerationContext, FQNOption.IgnoreNone)
+                ));
+            }
         }
 
         #endregion
@@ -1183,11 +1354,16 @@ public virtual bool CanGenerateMethod(Method method)
             {
                 return false;
             }
+            else if (Utils.FindDescribedTemplate(method) != null)
+            {
+                return false;
+            }
             return method.IsGenerated;
         }
 
         public virtual void GenerateMethod(Class @class, Method method)
         {
+            if (Utils.HasPossibleTemplateOverload(method))
             {
                 Write("static_cast<");
                 Write(method.ReturnType.Visit(new CppTypePrinter(Context)));
@@ -1220,6 +1396,43 @@ public virtual void GenerateMethod(Class @class, Method method)
                 Write(NamingStrategy.GetContextualName(method, GenerationContext, FQNOption.IgnoreNone));
                 Write(")");
             }
+            else if (Utils.HasPossibleOverload(method))
+            {
+                Write("::sol::resolve<");
+                Write(method.ReturnType.Visit(new CppTypePrinter(Context)));
+                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(")");
+            }
+            else
+            {
+                Write(string.Format("&{0}",
+                    NamingStrategy.GetContextualName(method, GenerationContext, FQNOption.IgnoreNone)
+                ));
+            }
         }
 
         #endregion
@@ -1284,5 +1497,573 @@ public override bool VisitTypeAliasDecl(TypeAlias typeAlias)
         }
 
         #endregion
+
+        #region Template
+
+        #region ClassDeclImported
+
+        public virtual string GetClassDeclImportedClassType(Class @class)
+        {
+            return "auto";
+        }
+
+        public virtual void GenerateClassDeclImportedClassValueType(Class @class)
+        {
+            var classContextualName = NamingStrategy.GetContextualName(@class, GenerationContext, FQNOption.IgnoreNone);
+            WriteLine($"using value_type = ::sol::usertype<{classContextualName}>;");
+        }
+
+        public virtual void GenerateClassDeclImportedClassBegin(Class @class)
+        {
+            WriteLine($"template <typename Importer>");
+            WriteLine($"struct {NamingStrategy.GetClassTemplateName(@class)} {{");
+            Indent();
+            GenerateClassDeclImportedClassValueType(@class);
+            GenerateDeclarationTemplateList(@class);
+            WriteLine(string.Format("template <typename {0}, typename {1} = {2}>",
+                Generator.GeneratorOptions.TemplateTypenameState,
+                Generator.GeneratorOptions.TemplateTypenameContext,
+                Generator.GeneratorOptions.TemplateContextDefaultType
+            ));
+            WriteLine(string.Format("{0} operator()({1}&& {2}, {3}&& {4} = {5}, const ::std::string& {6} = {{}}) {{",
+                GetClassDeclImportedClassType(@class),
+                Generator.GeneratorOptions.TemplateTypenameState,
+                Generator.GeneratorOptions.TemplateIdentifierState,
+                Generator.GeneratorOptions.TemplateTypenameContext,
+                Generator.GeneratorOptions.TemplateIdentifierContext,
+                Generator.GeneratorOptions.TemplateContextDefaultValue,
+                "name"
+            ));
+            Indent();
+        }
+
+        public virtual void GenerateClassDeclImportedClassEnd(Class @class)
+        {
+            Unindent();
+            WriteLine("}");
+            Unindent();
+            WriteLine("};");
+        }
+
+        public virtual void GenerateClassDeclImportedClassBody(Class @class)
+        {
+            var bindingName = NamingStrategy.GetBindingName(@class);
+            var contextualName = NamingStrategy.GetContextualName(@class, GenerationContext, FQNOption.IgnoreNone);
+            var fullyQualifiedName = NamingStrategy.GetFullyQualifiedName(@class, FQNOption.IgnoreNone);
+            var templateIdentifierContext = Generator.GeneratorOptions.TemplateIdentifierContext;
+            var templateIdentifierState = Generator.GeneratorOptions.TemplateIdentifierState;
+
+            WriteLine(string.Format("const char* {0} = typeid({1}).name();",
+                "__typeid_name",
+                contextualName
+            ));
+            WriteLine(string.Format("if ({0}[{1}] == ::sol::nil) {{",
+                templateIdentifierState,
+                "__typeid_name"
+            ));
+            Indent();
+
+            WriteLine(string.Format("/* FullyQualifiedName: {0} */",
+                fullyQualifiedName
+            ));
+            WriteLine(string.Format("auto {0} = {1}.template new_usertype<{2}>(",
+                bindingName,
+                templateIdentifierState,
+                contextualName
+            ));
+            Indent();
+            Write("__typeid_name");
+            GenerateClassDeclDeclarationList(@class, DetachmentOption.Off);
+            Unindent();
+            NewLine();
+            WriteLine(");");
+
+            Unindent();
+            WriteLine("}");
+            WriteLine(string.Format("if (!{0}.empty()) {{",
+                "name"
+            ));
+            Indent();
+            WriteLine(string.Format("{0}[{1}] = {2}[{3}];",
+                templateIdentifierContext,
+                "name",
+                templateIdentifierState,
+                "__typeid_name"
+            ));
+            Unindent();
+            WriteLine("}");
+            WriteLine(string.Format("return {0}[{1}];",
+                templateIdentifierState,
+                "__typeid_name"
+            ));
+        }
+
+        public virtual void GenerateClassDeclImportedClassPushContext(Class @class)
+        {
+            GenerationContext.PushTemplateLevel(1);
+            GenerationContext.PushRootContextName(Generator.GeneratorOptions.TemplateIdentifierState);
+            GenerationContext.PushCppContext(new CppContext()
+            {
+                FullyQualifiedName = string.Format("Importer::template {0}",
+                    NamingStrategy.GetQualifiedName(@class, FQNOption.IgnoreNone)
+                ),
+                Option = FQNOption.IgnoreNone
+            });
+        }
+
+        public virtual void GenerateClassDeclImportedClassPopContext(Class @class)
+        {
+            GenerationContext.PopCppContext();
+            GenerationContext.PopRootContextName();
+            GenerationContext.PopTemplateLevel();
+        }
+
+        public virtual bool IsClassDeclImported(Class @class)
+        {
+            return @class.Access == AccessSpecifier.Protected;
+        }
+
+        public virtual bool CanGenerateClassDeclImported(Class @class)
+        {
+            if (AlreadyVisited(@class))
+            {
+                return false;
+            }
+            else if (@class.Access != AccessSpecifier.Protected)
+            {
+                return false;
+            }
+            else if (@class.IsIncomplete)
+            {
+                return false;
+            }
+            else if (@class.IsUnion)
+            {
+                return false;
+            }
+            else if (!TemplateAllowed)
+            {
+                return false;
+            }
+            else if (Utils.FindDescribedTemplate(@class) != null)
+            {
+                return false;
+            }
+            return @class.IsGenerated;
+        }
+
+        public virtual void GenerateClassDeclImported(Class @class)
+        {
+            GenerateClassDeclImportedClassPushContext(@class);
+
+            GenerateClassDeclImportedClassBegin(@class);
+            GenerateClassDeclImportedClassBody(@class);
+            GenerateClassDeclImportedClassEnd(@class);
+
+            GenerateClassDeclImportedClassPopContext(@class);
+        }
+
+        #endregion
+
+        #region ClassTemplate
+
+        public virtual string GetClassTemplateDeclFunctorReturnType(ClassTemplate template)
+        {
+            return "auto";
+        }
+
+        public virtual void GenerateClassTemplateDeclFunctorValueType(ClassTemplate template)
+        {
+            var contextualName = NamingStrategy.GetContextualName(template, GenerationContext, FQNOption.IgnoreNone);
+
+            WriteLine(string.Format("using value_type = ::sol::usertype<{0}>;",
+                contextualName
+            ));
+        }
+
+        public virtual void GenerateClassTemplateDeclBegin(ClassTemplate template)
+        {
+            Write("template <");
+            if (template.Access == AccessSpecifier.Protected)
+            {
+                Write("typename Importer>");
+                if (template.Parameters.Count > 0)
+                {
+                    Write(", ");
+                }
+            }
+            Write(NamingStrategy.PrintClassTemplateParameters(template.Parameters, false, TemplateParameterOption.AsParameter));
+            WriteLine(">");
+            WriteLine($"struct {NamingStrategy.GetClassTemplateName(template)} {{");
+            Indent();
+            GenerateClassTemplateDeclFunctorValueType(template);
+            GenerateDeclarationTemplateList(template.TemplatedClass);
+            WriteLine(string.Format("template <typename {0}, typename {1} = {2}>",
+                Generator.GeneratorOptions.TemplateTypenameState,
+                Generator.GeneratorOptions.TemplateTypenameContext,
+                Generator.GeneratorOptions.TemplateContextDefaultType
+            ));
+            WriteLine(string.Format("{0} operator()({1}&& {2}, {3}&& {4} = {5}, const ::std::string& {6} = {{}}) {{",
+                GetClassTemplateDeclFunctorReturnType(template),
+                Generator.GeneratorOptions.TemplateTypenameState,
+                Generator.GeneratorOptions.TemplateIdentifierState,
+                Generator.GeneratorOptions.TemplateTypenameContext,
+                Generator.GeneratorOptions.TemplateIdentifierContext,
+                Generator.GeneratorOptions.TemplateContextDefaultValue,
+                "name"
+            ));
+            Indent();
+        }
+
+        public virtual void GenerateClassTemplateDeclEnd(ClassTemplate template)
+        {
+            Unindent();
+            WriteLine("}");
+            Unindent();
+            WriteLine("};");
+        }
+
+        public virtual void GenerateClassTemplateDeclBody(ClassTemplate template)
+        {
+            var bindingName = NamingStrategy.GetBindingName(template);
+            var contextualName = NamingStrategy.GetContextualName(template, GenerationContext, FQNOption.IgnoreNone);
+            var fullyQualifiedName = NamingStrategy.GetFullyQualifiedName(template, FQNOption.IgnoreNone);
+            var templateIdentifierContext = Generator.GeneratorOptions.TemplateIdentifierContext;
+            var templateIdentifierState = Generator.GeneratorOptions.TemplateIdentifierState;
+
+            WriteLine(string.Format("const char* {0} = typeid({1}).name();",
+                "__typeid_name",
+                contextualName
+            ));
+            WriteLine(string.Format("if ({0}[{1}] == ::sol::nil) {{",
+                templateIdentifierState,
+                "__typeid_name"
+            ));
+            Indent();
+
+            WriteLine(string.Format("/* FullyQualifiedName: {0} */",
+                fullyQualifiedName
+            ));
+            WriteLine(string.Format("auto {0} = {1}.template new_usertype<{2}>(",
+                bindingName,
+                templateIdentifierState,
+                contextualName
+            ));
+            Indent();
+            Write("__typeid_name");
+            GenerateClassDeclDeclarationList(template.TemplatedClass, DetachmentOption.Off);
+            Unindent();
+            NewLine();
+            WriteLine(");");
+
+            Unindent();
+            WriteLine("}");
+            WriteLine(string.Format("if (!{0}.empty()) {{",
+                "name"
+            ));
+            Indent();
+            WriteLine(string.Format("{0}[{1}] = {2}[{3}];",
+                templateIdentifierContext,
+                "name",
+                templateIdentifierState,
+                "__typeid_name"
+            ));
+            Unindent();
+            WriteLine("}");
+            WriteLine(string.Format("return {0}[{1}];",
+                templateIdentifierState,
+                "__typeid_name"
+            ));
+        }
+
+        public virtual void GenerateClassTemplateDeclPushContext(ClassTemplate template)
+        {
+            GenerationContext.PushTemplateLevel(1);
+            GenerationContext.PushRootContextName(Generator.GeneratorOptions.TemplateIdentifierState);
+            if (template.Access == AccessSpecifier.Protected)
+            {
+                if (Generator.GeneratorOptions.ImportedTemplateMode == ImportedClassTemplateMode.Indirect)
+                {
+                    GenerationContext.PushCppContext(new CppContext()
+                    {
+                        FullyQualifiedName = string.Format("Temp_{0}",
+                            NamingStrategy.GetQualifiedName(template, FQNOption.IgnoreNone)
+                        )
+                    });
+                }
+                else
+                {
+                    GenerationContext.PushCppContext(new CppContext()
+                    {
+                        FullyQualifiedName = string.Format("Importer::template {0}",
+                            NamingStrategy.GetQualifiedName(template, FQNOption.IgnoreNone)
+                        )
+                    });
+                }
+            }
+        }
+
+        public virtual void GenerateClassTemplateDeclPopContext(ClassTemplate template)
+        {
+            if (template.Access == AccessSpecifier.Protected)
+            {
+                GenerationContext.PopCppContext();
+            }
+            GenerationContext.PopRootContextName();
+            GenerationContext.PopTemplateLevel();
+        }
+
+        public virtual bool CanGenerateClassTemplateDecl(ClassTemplate template)
+        {
+            if (AlreadyVisited(template))
+            {
+                return false;
+            }
+            else if (template.Access == AccessSpecifier.Private)
+            {
+                return false;
+            }
+            else if (template.IsIncomplete)
+            {
+                return false;
+            }
+            else if (!TemplateAllowed)
+            {
+                return false;
+            }
+            return template.IsGenerated;
+        }
+
+        public virtual void GenerateClassTemplateDecl(ClassTemplate template)
+        {
+            GenerateClassTemplateDeclPushContext(template);
+
+            GenerateClassTemplateDeclBegin(template);
+            GenerateClassTemplateDeclBody(template);
+            GenerateClassTemplateDeclEnd(template);
+
+            GenerateClassTemplateDeclPopContext(template);
+        }
+
+        public override bool VisitClassTemplateDecl(ClassTemplate template)
+        {
+            if (!CanGenerateClassTemplateDecl(template))
+            {
+                return false;
+            }
+
+            GenerateClassTemplateDecl(template);
+
+            return true;
+        }
+
+        #endregion
+
+        #region ClassTemplateSpecialization
+
+        public virtual string GetClassTemplateSpecializationDeclFunctorReturnType(ClassTemplateSpecialization specialization)
+        {
+            return "auto";
+        }
+
+        public virtual void GenerateClassTemplateSpecializationDeclFunctorValueType(ClassTemplateSpecialization specialization)
+        {
+            var contextualName = NamingStrategy.GetContextualName(specialization, GenerationContext, FQNOption.IgnoreNone);
+
+            WriteLine(string.Format("using value_type = ::sol::usertype<{0}>;",
+                contextualName
+            ));
+        }
+
+        public virtual void GenerateClassTemplateSpecializationDeclBegin(ClassTemplateSpecialization specialization)
+        {
+            Write("template <");
+            if (specialization.Access == AccessSpecifier.Protected)
+            {
+                Write("typename Importer>");
+                if (specialization is ClassTemplatePartialSpecialization)
+                {
+                    // TODO: provisional and WRONG: see https://github.com/mono/CppSharp/issues/1801
+                    if (specialization.TemplatedDecl.Parameters.Count > 0)
+                    {
+                        Write(", ");
+                    }
+                }
+            }
+            if (specialization is ClassTemplatePartialSpecialization)
+            {
+                // TODO: provisional and WRONG: see https://github.com/mono/CppSharp/issues/1801
+                Write(NamingStrategy.PrintClassTemplateParameters(specialization.TemplatedDecl.Parameters, false, TemplateParameterOption.AsParameter));
+            }
+            WriteLine(">");
+            WriteLine(string.Format("struct {0}{1} {{",
+                NamingStrategy.GetClassTemplateName(specialization),
+                NamingStrategy.PrintClassTemplateSpecializationArguments(specialization.Arguments, true)
+            ));
+            Indent();
+            GenerateClassTemplateSpecializationDeclFunctorValueType(specialization);
+            GenerateDeclarationTemplateList(specialization);
+            WriteLine(string.Format("template <typename {0}, typename {1} = {2}>",
+                Generator.GeneratorOptions.TemplateTypenameState,
+                Generator.GeneratorOptions.TemplateTypenameContext,
+                Generator.GeneratorOptions.TemplateContextDefaultType
+            ));
+            WriteLine(string.Format("{0} operator()({1}&& {2}, {3}&& {4} = {5}, const ::std::string& {6} = {{}}) {{",
+                GetClassTemplateSpecializationDeclFunctorReturnType(specialization),
+                Generator.GeneratorOptions.TemplateTypenameState,
+                Generator.GeneratorOptions.TemplateIdentifierState,
+                Generator.GeneratorOptions.TemplateTypenameContext,
+                Generator.GeneratorOptions.TemplateIdentifierContext,
+                Generator.GeneratorOptions.TemplateContextDefaultValue,
+                "name"
+            ));
+            Indent();
+        }
+
+        public virtual void GenerateClassTemplateSpecializationDeclEnd(ClassTemplateSpecialization specialization)
+        {
+            Unindent();
+            WriteLine("}");
+            Unindent();
+            WriteLine("};");
+        }
+
+        public virtual void GenerateClassTemplateSpecializationDeclBody(ClassTemplateSpecialization specialization)
+        {
+            var bindingName = NamingStrategy.GetBindingName(specialization);
+            var contextualName = NamingStrategy.GetContextualName(specialization, GenerationContext, FQNOption.IgnoreNone);
+            var fullyQualifiedName = NamingStrategy.GetFullyQualifiedName(specialization, FQNOption.IgnoreNone);
+            var templateIdentifierContext = Generator.GeneratorOptions.TemplateIdentifierContext;
+            var templateIdentifierState = Generator.GeneratorOptions.TemplateIdentifierState;
+
+            WriteLine(string.Format("const char* {0} = typeid({1}).name();",
+                "__typeid_name",
+                contextualName
+            ));
+            WriteLine(string.Format("if ({0}[{1}] == ::sol::nil) {{",
+                templateIdentifierState,
+                "__typeid_name"
+            ));
+            Indent();
+
+            WriteLine(string.Format("/* FullyQualifiedName: {0} */",
+                fullyQualifiedName
+            ));
+            WriteLine(string.Format("auto {0} = {1}.template new_usertype<{2}>(",
+                bindingName,
+                templateIdentifierState,
+                contextualName
+            ));
+            Indent();
+            Write("__typeid_name");
+            GenerateClassDeclDeclarationList(specialization, DetachmentOption.Off);
+            Unindent();
+            NewLine();
+            WriteLine(");");
+
+            Unindent();
+            WriteLine("}");
+            WriteLine(string.Format("if (!{0}.empty()) {{",
+                "name"
+            ));
+            Indent();
+            WriteLine(string.Format("{0}[{1}] = {2}[{3}];",
+                templateIdentifierContext,
+                "name",
+                templateIdentifierState,
+                "__typeid_name"
+            ));
+            Unindent();
+            WriteLine("}");
+            WriteLine(string.Format("return {0}[{1}];",
+                templateIdentifierState,
+                "__typeid_name"
+            ));
+        }
+
+        public virtual void GenerateClassTemplateSpecializationDeclPushContext(ClassTemplateSpecialization specialization)
+        {
+            GenerationContext.PushTemplateLevel(1);
+            GenerationContext.PushRootContextName(Generator.GeneratorOptions.TemplateIdentifierState);
+            if (specialization.Access == AccessSpecifier.Protected)
+            {
+                if (Generator.GeneratorOptions.ImportedTemplateMode == ImportedClassTemplateMode.Indirect)
+                {
+                    GenerationContext.PushCppContext(new CppContext()
+                    {
+                        FullyQualifiedName = string.Format("Temp_{0}",
+                            NamingStrategy.GetQualifiedName(specialization, FQNOption.IgnoreNone)
+                        )
+                    });
+                }
+                else
+                {
+                    GenerationContext.PushCppContext(new CppContext()
+                    {
+                        FullyQualifiedName = string.Format("Importer::template {0}",
+                            NamingStrategy.GetQualifiedName(specialization, FQNOption.IgnoreNone)
+                        )
+                    });
+                }
+            }
+        }
+
+        public virtual void GenerateClassTemplateSpecializationDeclPopContext(ClassTemplateSpecialization specialization)
+        {
+            if (specialization.Access == AccessSpecifier.Protected)
+            {
+                GenerationContext.PopCppContext();
+            }
+            GenerationContext.PopRootContextName();
+            GenerationContext.PopTemplateLevel();
+        }
+
+        public virtual bool CanGenerateClassTemplateSpecializationDecl(ClassTemplateSpecialization specialization)
+        {
+            if (AlreadyVisited(specialization))
+            {
+                return false;
+            }
+            else if (specialization.Access == AccessSpecifier.Private)
+            {
+                return false;
+            }
+            else if (specialization.IsIncomplete)
+            {
+                return false;
+            }
+            else if (!TemplateAllowed)
+            {
+                return false;
+            }
+            return specialization.IsGenerated;
+        }
+
+        public virtual void GenerateClassTemplateSpecializationDecl(ClassTemplateSpecialization specialization)
+        {
+            GenerateClassTemplateSpecializationDeclPushContext(specialization);
+
+            GenerateClassTemplateSpecializationDeclBegin(specialization);
+            GenerateClassTemplateSpecializationDeclBody(specialization);
+            GenerateClassTemplateSpecializationDeclEnd(specialization);
+
+            GenerateClassTemplateSpecializationDeclPopContext(specialization);
+        }
+
+        public override bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecialization specialization)
+        {
+            if (!CanGenerateClassTemplateSpecializationDecl(specialization))
+            {
+                return false;
+            }
+
+            GenerateClassTemplateSpecializationDecl(specialization);
+
+            return true;
+        }
+
+        #endregion
+
+        #endregion
     }
 }
diff --git a/src/Generator/Generators/Registrable/RegistrableGeneratorContext.cs b/src/Generator/Generators/Registrable/RegistrableGeneratorContext.cs
index 25c1c9ce1..2b55f8f92 100644
--- a/src/Generator/Generators/Registrable/RegistrableGeneratorContext.cs
+++ b/src/Generator/Generators/Registrable/RegistrableGeneratorContext.cs
@@ -100,13 +100,16 @@ public int PopTemplateLevel()
     public class CppContext
     {
         public string FullyQualifiedName { get; set; }
-        public FQNOption Option { get; set; }
+        public FQNOption Option { get; set; } = FQNOption.IgnoreAll;
 
         public string GetFullQualifiedName(FQNOption option)
         {
-            if (!(Option | option).IgnoreTemplateTypenameKeyword)
+            if (!option.IgnoreTemplateTypenameKeyword)
             {
-                return "typename " + FullyQualifiedName;
+                if (!Option.IgnoreTemplateTypenameKeyword)
+                {
+                    return "typename " + FullyQualifiedName;
+                }
             }
             return FullyQualifiedName;
         }
diff --git a/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs b/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs
index 037fea4eb..e831031d5 100644
--- a/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs
+++ b/src/Generator/Generators/Registrable/RegistrableNamingStrategy.cs
@@ -124,7 +124,10 @@ public virtual string PrintClassTemplateParameter(Declaration declaration, Templ
         public virtual string PrintClassTemplateParameters(List<Declaration> parameters, bool includeEnclosingBrackets, TemplateParameterOption option)
         {
             var builder = new StringBuilder();
-            builder.Append('<');
+            if (includeEnclosingBrackets)
+            {
+                builder.Append('<');
+            }
             for (int i = 0; i < parameters.Count; i++)
             {
                 if (i > 0)
@@ -133,7 +136,10 @@ public virtual string PrintClassTemplateParameters(List<Declaration> parameters,
                 }
                 builder.Append(PrintClassTemplateParameter(parameters[i], option));
             }
-            builder.Append('>');
+            if (includeEnclosingBrackets)
+            {
+                builder.Append('>');
+            }
             return builder.ToString();
         }
 
@@ -149,7 +155,10 @@ public virtual string PrintClassTemplateSpecializationArgument(TemplateArgument
         public virtual string PrintClassTemplateSpecializationArguments(List<TemplateArgument> arguments, bool includeEnclosingBrackets)
         {
             var builder = new StringBuilder();
-            builder.Append('<');
+            if (includeEnclosingBrackets)
+            {
+                builder.Append('<');
+            }
             for (int i = 0; i < arguments.Count; i++)
             {
                 if (i > 0)
@@ -158,7 +167,10 @@ public virtual string PrintClassTemplateSpecializationArguments(List<TemplateArg
                 }
                 builder.Append(PrintClassTemplateSpecializationArgument(arguments[i]));
             }
-            builder.Append('>');
+            if (includeEnclosingBrackets)
+            {
+                builder.Append('>');
+            }
             return builder.ToString();
         }
 
@@ -181,9 +193,14 @@ public virtual string GetQualifiedName(Declaration declaration, FQNOption option
             }
             else
             {
-                if (currentDeclaration is not ClassTemplate template)
+                Template template = null;
+                if (currentDeclaration is not ClassTemplate)
                 {
-                    template = (ClassTemplate)Utils.FindDescribedTemplate(currentDeclaration);
+                    var describedTemplate = Utils.FindDescribedTemplate(currentDeclaration);
+                    if (describedTemplate is ClassTemplate)
+                    {
+                        template = (ClassTemplate)describedTemplate;
+                    }
                 }
                 if (template != null)
                 {
@@ -287,6 +304,31 @@ public virtual string GetFullyQualifiedName(Declaration declaration, FQNOption o
 
         public virtual string GetContextualName(Declaration declaration, RegistrableGeneratorContext context, FQNOption option)
         {
+            Class @class = null;
+            Template template = null;
+            if (declaration is Class)
+            {
+                @class = declaration as Class;
+                template = Utils.FindDescribedTemplate(declaration);
+            }
+            else if (declaration is ClassTemplate classTemplate)
+            {
+                @class = classTemplate.TemplatedClass;
+                template = classTemplate;
+            }
+            if (@class is Class)
+            {
+                if (template is ClassTemplate)
+                {
+                    // TODO: check if ClassTemplate is collapsible
+                }
+
+                if (@class.Access == AccessSpecifier.Protected)
+                {
+                    return GetCppContext(@class, context, FQNOption.IgnoreNone);
+                }
+                return GetFullyQualifiedName(declaration, option);
+            }
             return GetCppContext(declaration, context, new FQNOption(false, true, false, false)) + "::" + GetQualifiedName(declaration, option);
         }
 
@@ -409,5 +451,10 @@ public virtual string GetMembershipScopeName(Function function, RegistrableGener
             }
             return "";
         }
+
+        public virtual string GetClassTemplateName(Declaration declaration)
+        {
+            return $"functor_{GetRegistrationFunctionName(declaration)}";
+        }
     }
 }
diff --git a/src/Generator/Generators/Registrable/Utils/Utils.cs b/src/Generator/Generators/Registrable/Utils/Utils.cs
index ef03bbb5c..ebca3efd3 100644
--- a/src/Generator/Generators/Registrable/Utils/Utils.cs
+++ b/src/Generator/Generators/Registrable/Utils/Utils.cs
@@ -1,10 +1,13 @@
 using CppSharp.AST;
+using System;
+using System.Collections.Generic;
+using System.Linq;
 
 namespace CppSharp.Generators.Registrable
 {
     public static class Utils
     {
-        public static Declaration FindDescribedTemplate(Declaration declaration)
+        public static Template FindDescribedTemplate(Declaration declaration)
         {
             foreach (var template in declaration.Namespace.Templates)
             {
@@ -20,5 +23,117 @@ public static DetachmentOption FindDetachmentOption(Declaration declaration)
         {
             return (declaration.Namespace is Class) ? DetachmentOption.Off : DetachmentOption.On;
         }
+
+        public static bool HasPossibleOverload(Function function)
+        {
+            var parent = function.OriginalNamespace;
+            if (parent is Class @class)
+            {
+                foreach (var item in @class.Methods)
+                {
+                    if (item.OriginalFunction == null)
+                    {
+                        if (item != function)
+                        {
+                            if (item.OriginalName == function.Name)
+                            {
+                                return true;
+                            }
+                        }
+                    }
+                }
+                foreach (var item in @class.Functions)
+                {
+                    if (item.OriginalFunction == null)
+                    {
+                        if (item != function)
+                        {
+                            if (item.OriginalName == function.Name)
+                            {
+                                return true;
+                            }
+                        }
+                    }
+                }
+                foreach (var item in @class.Templates.Where(template => template is FunctionTemplate).Cast<FunctionTemplate>())
+                {
+                    var templatedFunction = item.TemplatedFunction;
+                    if (templatedFunction.OriginalFunction == null)
+                    {
+                        if (templatedFunction != function)
+                        {
+                            if (templatedFunction.OriginalName == function.Name)
+                            {
+                                return true;
+                            }
+                        }
+                    }
+                }
+                return false;
+            }
+            return true;
+        }
+
+        public static bool HasPossibleTemplateOverload(Function function)
+        {
+            var parent = function.OriginalNamespace;
+            if (parent is Class @class)
+            {
+                foreach (var item in @class.Templates.Where(template => template is FunctionTemplate).Cast<FunctionTemplate>())
+                {
+                    var templatedFunction = item.TemplatedFunction;
+                    if (templatedFunction.OriginalFunction == null)
+                    {
+                        if (templatedFunction != function)
+                        {
+                            if (templatedFunction.OriginalName == function.Name)
+                            {
+                                return true;
+                            }
+                        }
+                    }
+                }
+                return false;
+            }
+            return true;
+        }
+
+        public static bool HasPossibleTemplateOverload(Method method)
+        {
+            if (method.Kind == CXXMethodKind.UsingDirective)
+            {
+                return true;
+            }
+            return HasPossibleTemplateOverload(method as Function);
+        }
+
+        public static bool IsDefaultTemplateParameter(Declaration parameter)
+        {
+            if (parameter is TypeTemplateParameter typeTemplateParameter)
+            {
+                return typeTemplateParameter.DefaultArgument.Type != null;
+            }
+            else if (parameter is NonTypeTemplateParameter nonTypeTemplateParameter)
+            {
+                return nonTypeTemplateParameter.DefaultArgument != null;
+            }
+            else if (parameter is TemplateTemplateParameter templateTemplateParameter)
+            {
+                throw new InvalidOperationException();
+            }
+            throw new InvalidOperationException();
+        }
+
+        public static bool IsDefaultTemplateParameterList(List<Declaration> parameters)
+        {
+            foreach (var parameter in parameters)
+            {
+                if (!IsDefaultTemplateParameter(parameter))
+                {
+                    return false;
+                }
+            }
+            return true;
+        }
     }
 }

From c12d4e7a9a02f088f6ca6d9452a5990e29ee00e7 Mon Sep 17 00:00:00 2001
From: Deadlocklogic <deadlocklogic@gmail.com>
Date: Sun, 17 Dec 2023 17:58:14 +0200
Subject: [PATCH 12/13] LuaSolSources: fix ClassTemplatePartialSpecialization
 Parameters

---
 .../Generators/Registrable/Lua/Sol/LuaSolSources.cs   | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs
index 84a468376..f1a15576b 100644
--- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs
+++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolSources.cs
@@ -1877,23 +1877,22 @@ public virtual void GenerateClassTemplateSpecializationDeclFunctorValueType(Clas
 
         public virtual void GenerateClassTemplateSpecializationDeclBegin(ClassTemplateSpecialization specialization)
         {
+            ClassTemplatePartialSpecialization classTemplatePartialSpecialization = specialization as ClassTemplatePartialSpecialization;
             Write("template <");
             if (specialization.Access == AccessSpecifier.Protected)
             {
                 Write("typename Importer>");
-                if (specialization is ClassTemplatePartialSpecialization)
+                if (classTemplatePartialSpecialization != null)
                 {
-                    // TODO: provisional and WRONG: see https://github.com/mono/CppSharp/issues/1801
-                    if (specialization.TemplatedDecl.Parameters.Count > 0)
+                    if (classTemplatePartialSpecialization.Parameters.Count > 0)
                     {
                         Write(", ");
                     }
                 }
             }
-            if (specialization is ClassTemplatePartialSpecialization)
+            if (classTemplatePartialSpecialization != null)
             {
-                // TODO: provisional and WRONG: see https://github.com/mono/CppSharp/issues/1801
-                Write(NamingStrategy.PrintClassTemplateParameters(specialization.TemplatedDecl.Parameters, false, TemplateParameterOption.AsParameter));
+                Write(NamingStrategy.PrintClassTemplateParameters(classTemplatePartialSpecialization.Parameters, false, TemplateParameterOption.AsParameter));
             }
             WriteLine(">");
             WriteLine(string.Format("struct {0}{1} {{",

From 11b37ba40f5f03852d987dcdd3a23900286a52d5 Mon Sep 17 00:00:00 2001
From: Deadlocklogic <deadlocklogic@gmail.com>
Date: Sun, 17 Dec 2023 20:57:12 +0200
Subject: [PATCH 13/13] Improve RegistrableGeneratorOptions + prepare
 boilerplate code

---
 .../Registrable/Lua/Sol/LuaSolGenerator.cs    |  8 ++--
 .../Lua/Sol/LuaSolGeneratorOptions.cs         |  2 +-
 .../Registrable/RegistrableGenerator.cs       | 44 ++++++++++++++++---
 .../RegistrableGeneratorOptions.cs            | 17 +++++--
 .../Registrable/RegistrableModuleHeader.cs    | 19 ++++++++
 .../Registrable/RegistrableModuleSource.cs    | 19 ++++++++
 6 files changed, 92 insertions(+), 17 deletions(-)
 create mode 100644 src/Generator/Generators/Registrable/RegistrableModuleHeader.cs
 create mode 100644 src/Generator/Generators/Registrable/RegistrableModuleSource.cs

diff --git a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs
index ff55e533e..ddb2faeeb 100644
--- a/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs
+++ b/src/Generator/Generators/Registrable/Lua/Sol/LuaSolGenerator.cs
@@ -12,21 +12,19 @@ public LuaSolGenerator(BindingContext context) : base(context)
         {
         }
 
-        protected override LuaSolGeneratorOptions CreateOptions(RegistrableGenerator<LuaSolGeneratorOptions, LuaSolHeaders, LuaSolSources> generator)
+        protected override LuaSolGeneratorOptions CreateOptions()
         {
             return new LuaSolGeneratorOptions(this);
         }
 
-        protected override LuaSolHeaders CreateHeader(RegistrableGenerator<LuaSolGeneratorOptions, LuaSolHeaders, LuaSolSources> generator, IEnumerable<TranslationUnit> units)
+        protected override LuaSolHeaders CreateHeader(IEnumerable<TranslationUnit> units)
         {
             return new LuaSolHeaders(this, units);
         }
 
-        protected override LuaSolSources CreateSource(RegistrableGenerator<LuaSolGeneratorOptions, LuaSolHeaders, LuaSolSources> generator, IEnumerable<TranslationUnit> units)
+        protected override LuaSolSources CreateSource(IEnumerable<TranslationUnit> 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 1948b7d1d..32531c212 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<LuaSolGenerator>
+    public class LuaSolGeneratorOptions : TRegistrableGeneratorOptions<LuaSolGenerator>
     {
         public LuaSolNamingStrategy NamingStrategy;
 
diff --git a/src/Generator/Generators/Registrable/RegistrableGenerator.cs b/src/Generator/Generators/Registrable/RegistrableGenerator.cs
index 670e111cb..00017d80b 100644
--- a/src/Generator/Generators/Registrable/RegistrableGenerator.cs
+++ b/src/Generator/Generators/Registrable/RegistrableGenerator.cs
@@ -1,34 +1,64 @@
 using CppSharp.AST;
 using System.Collections.Generic;
+using System.IO;
 
 namespace CppSharp.Generators.Registrable
 {
     public abstract class RegistrableGenerator<TOptions, THeader, TSource> : Generator
+        where TOptions : RegistrableGeneratorOptions
         where THeader : CodeGenerator
         where TSource : CodeGenerator
     {
         public TOptions GeneratorOptions { get; }
 
+        public TranslationUnit GlobalTranslationUnit { get; private set; }
+
+        public TranslationUnit InheritanceTranslationUnit { get; private set; }
+
+        // TODO: Implement when Generator interface is cleaner
+        // public CodeGenerator ModuleHeaderCodeGenerator { get; private set; }
+
+        // TODO: Implement when Generator interface is cleaner
+        //public CodeGenerator ModuleSourceCodeGenerator { get; private set; }
+
         public RegistrableGenerator(BindingContext context) : base(context)
         {
-            GeneratorOptions = CreateOptions(this);
+            GeneratorOptions = CreateOptions();
         }
 
-        protected abstract TOptions CreateOptions(RegistrableGenerator<TOptions, THeader, TSource> generator);
+        protected abstract TOptions CreateOptions();
 
-        protected abstract THeader CreateHeader(RegistrableGenerator<TOptions, THeader, TSource> generator, IEnumerable<TranslationUnit> units);
+        protected abstract THeader CreateHeader(IEnumerable<TranslationUnit> units);
 
-        protected abstract TSource CreateSource(RegistrableGenerator<TOptions, THeader, TSource> generator, IEnumerable<TranslationUnit> units);
+        protected abstract TSource CreateSource(IEnumerable<TranslationUnit> units);
 
         public override List<CodeGenerator> Generate(IEnumerable<TranslationUnit> units)
         {
             return new List<CodeGenerator>
             {
-                CreateHeader(this, units),
-                CreateSource(this, units)
+                CreateHeader(units),
+                CreateSource(units)
             };
         }
 
-        public override bool SetupPasses() => true;
+        // TODO: Should be a better method for this maybe Configure.
+        public override bool SetupPasses()
+        {
+            {
+                var module = Context.Options.Modules[1];
+                GlobalTranslationUnit = Context.ASTContext.FindOrCreateTranslationUnit(
+                    Path.Combine(Context.Options.OutputDir, GeneratorOptions.OutputSubDir, "@package", "global.h")
+                );
+                GlobalTranslationUnit.Module = module;
+            }
+            {
+                var module = Context.Options.Modules[1];
+                InheritanceTranslationUnit = Context.ASTContext.FindOrCreateTranslationUnit(
+                    Path.Combine(Context.Options.OutputDir, GeneratorOptions.OutputSubDir, "@package", "inheritance.h")
+                );
+                InheritanceTranslationUnit.Module = module;
+            }
+            return true;
+        }
     }
 }
diff --git a/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs b/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs
index 04dfb8927..d8b1b7371 100644
--- a/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs
+++ b/src/Generator/Generators/Registrable/RegistrableGeneratorOptions.cs
@@ -9,12 +9,11 @@ public enum ImportedClassTemplateMode
         Import
     }
 
-    public abstract class RegistrableGeneratorOptions<TGenerator>
-        where TGenerator : Generator
+    public abstract class RegistrableGeneratorOptions
     {
         public delegate string Delegate(string name);
 
-        public TGenerator Generator { get; set; }
+        public virtual Generator Generator { get; set; }
 
         public virtual string OutputSubDir { get; }
         public virtual string RootContextType { get; }
@@ -60,7 +59,7 @@ public abstract class RegistrableGeneratorOptions<TGenerator>
         public virtual string DefaultStaticCastFunctionTemplateFullyQualifiedName => null;
         public virtual string DefaultDynamicCastFunctionTemplateFullyQualifiedName => null;
 
-        public RegistrableGeneratorOptions(TGenerator generator)
+        public RegistrableGeneratorOptions(Generator generator)
         {
             Generator = generator;
             OutputSubDir = DefaultOutputSubdir;
@@ -86,4 +85,14 @@ public RegistrableGeneratorOptions(TGenerator generator)
             DynamicCastFunctionTemplateFullyQualifiedName = DefaultDynamicCastFunctionTemplateFullyQualifiedName;
         }
     }
+
+    public abstract class TRegistrableGeneratorOptions<TGenerator> : RegistrableGeneratorOptions
+        where TGenerator : Generator
+    {
+        public override TGenerator Generator => (TGenerator)base.Generator;
+
+        public TRegistrableGeneratorOptions(TGenerator generator) : base(generator)
+        {
+        }
+    }
 }
diff --git a/src/Generator/Generators/Registrable/RegistrableModuleHeader.cs b/src/Generator/Generators/Registrable/RegistrableModuleHeader.cs
new file mode 100644
index 000000000..b9b7ac55d
--- /dev/null
+++ b/src/Generator/Generators/Registrable/RegistrableModuleHeader.cs
@@ -0,0 +1,19 @@
+using CppSharp.AST;
+using System.Collections.Generic;
+
+namespace CppSharp.Generators.Registrable
+{
+    public class RegistrableModuleHeader<TGenerator> : RegistrableCodeGenerator<TGenerator>
+        where TGenerator : Generator
+    {
+        public RegistrableModuleHeader(TGenerator generator, IEnumerable<TranslationUnit> units) : base(generator, units)
+        {
+        }
+
+        public override string FileExtension { get; } = "h";
+
+        public override void Process()
+        {
+        }
+    }
+}
diff --git a/src/Generator/Generators/Registrable/RegistrableModuleSource.cs b/src/Generator/Generators/Registrable/RegistrableModuleSource.cs
new file mode 100644
index 000000000..2546fd216
--- /dev/null
+++ b/src/Generator/Generators/Registrable/RegistrableModuleSource.cs
@@ -0,0 +1,19 @@
+using CppSharp.AST;
+using System.Collections.Generic;
+
+namespace CppSharp.Generators.Registrable
+{
+    public class RegistrableModuleSource<TGenerator> : RegistrableCodeGenerator<TGenerator>
+        where TGenerator : Generator
+    {
+        public RegistrableModuleSource(TGenerator generator, IEnumerable<TranslationUnit> units) : base(generator, units)
+        {
+        }
+
+        public override string FileExtension { get; } = "cpp";
+
+        public override void Process()
+        {
+        }
+    }
+}