From 6308cf4c3ca8a1a3e0cdb15387182aac1515418b Mon Sep 17 00:00:00 2001 From: triton Date: Sun, 14 Jul 2013 19:28:53 +0100 Subject: [PATCH] Added a new templating system based on typed "text blocks", allowing a lot more customization after the initial text is generated. The design might still change a bit in the future, but this is a good first step in getting things in the final direction without having to change too much the current generators. --- .../Generators/CLI/CLIHeadersTemplate.cs | 27 +++++- .../Generators/CLI/CLISourcesTemplate.cs | 41 ++++++--- .../Generators/CLI/CLITextTemplate.cs | 41 ++++++++- .../Generators/CSharp/CSharpTextTemplate.cs | 9 +- src/Generator/Generators/Template.cs | 92 ++++++++++++++++++- 5 files changed, 180 insertions(+), 30 deletions(-) diff --git a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs index 45ab2364..edeefa3c 100644 --- a/src/Generator/Generators/CLI/CLIHeadersTemplate.cs +++ b/src/Generator/Generators/CLI/CLIHeadersTemplate.cs @@ -17,22 +17,29 @@ namespace CppSharp.Generators.CLI public CLIHeadersTemplate(Driver driver, TranslationUnit unit) : base(driver, unit) { - } - public override void Generate() + public override void GenerateBlocks() { - OnStart(this); + PushBlock(CLIBlockKind.Header); + PopBlock(); + PushBlock(CLIBlockKind.Includes); WriteLine("#pragma once"); NewLine(); + PushBlock(CLIBlockKind.IncludesForwardReferences); WriteLine("#include <{0}>", TranslationUnit.IncludePath); GenerateIncludeForwardRefs(); NewLine(); + PopBlock(); + PopBlock(); GenerateNamespace(TranslationUnit); + + PushBlock(CLIBlockKind.Footer); + PopBlock(); } public void GenerateIncludeForwardRefs() @@ -96,6 +103,7 @@ namespace CppSharp.Generators.CLI if (generateNamespace) { + PushBlock(CLIBlockKind.Namespace); WriteLine("namespace {0}", isTopLevel ? Options.OutputNamespace : SafeIdentifier(@namespace.Name)); @@ -103,7 +111,9 @@ namespace CppSharp.Generators.CLI } // Generate the forward references. + PushBlock(CLIBlockKind.ForwardReferences); GenerateForwardRefs(@namespace); + PopBlock(); // Generate all the enum declarations for the module. for (var i = 0; i < @namespace.Enums.Count; ++i) @@ -113,11 +123,13 @@ namespace CppSharp.Generators.CLI if (@enum.Ignore || @enum.IsIncomplete) continue; + PushBlock(CLIBlockKind.Enum); GenerateEnum(@enum); NeedNewLine(); if (i < @namespace.Enums.Count - 1) NewLine(); + PopBlock(); } NewLineIfNeeded(); @@ -136,11 +148,13 @@ namespace CppSharp.Generators.CLI if (@class.IsOpaque) continue; + PushBlock(CLIBlockKind.Class); GenerateClass(@class); NeedNewLine(); if (i < @namespace.Classes.Count - 1) NewLine(); + PopBlock(); } if (@namespace.HasFunctions) @@ -155,6 +169,7 @@ namespace CppSharp.Generators.CLI if (generateNamespace) { WriteCloseBraceIndent(); + PopBlock(); } } @@ -169,6 +184,7 @@ namespace CppSharp.Generators.CLI continue; NewLine(); + PopBlock(); } } @@ -532,11 +548,12 @@ namespace CppSharp.Generators.CLI if (typedef.Ignore) return false; - GenerateDeclarationCommon(typedef); - FunctionType function; if (typedef.Type.IsPointerTo(out function)) { + PushBlock(CLIBlockKind.Typedef); + GenerateDeclarationCommon(typedef); + WriteLine("public {0};", string.Format(TypePrinter.VisitDelegate(function), SafeIdentifier(typedef.Name))); diff --git a/src/Generator/Generators/CLI/CLISourcesTemplate.cs b/src/Generator/Generators/CLI/CLISourcesTemplate.cs index 2dd350a0..ff8c6dbf 100644 --- a/src/Generator/Generators/CLI/CLISourcesTemplate.cs +++ b/src/Generator/Generators/CLI/CLISourcesTemplate.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using CppSharp.AST; using CppSharp.Types; namespace CppSharp.Generators.CLI @@ -18,35 +19,42 @@ namespace CppSharp.Generators.CLI } - public override void Generate() + public override void GenerateBlocks() { - OnStart(this); + PushBlock(CLIBlockKind.Header); + PopBlock(); - var file = Path.GetFileNameWithoutExtension(TranslationUnit.FileName).Replace('\\', '/'); + var file = Path.GetFileNameWithoutExtension(TranslationUnit.FileName) + .Replace('\\', '/'); if (Driver.Options.GenerateName != null) file = Driver.Options.GenerateName(TranslationUnit); + PushBlock(CLIBlockKind.Includes); WriteLine("#include \"{0}.h\"", file); - GenerateForwardReferenceHeaders(); if (Options.OutputInteropIncludes) WriteLine("#include "); NewLine(); + PopBlock(); + PushBlock(CLIBlockKind.Usings); WriteLine("using namespace System;"); WriteLine("using namespace System::Runtime::InteropServices;"); - - OnNamespaces(this); NewLine(); + PopBlock(); - GenerateDeclarations(); + GenerateNamespace(TranslationUnit); + + PushBlock(CLIBlockKind.Footer); + PopBlock(); } public void GenerateForwardReferenceHeaders() { + PushBlock(CLIBlockKind.IncludesForwardReferences); var includes = new SortedSet(StringComparer.InvariantCulture); var typeRefs = TranslationUnit.TypeReferences as TypeRefsVisitor; @@ -81,15 +89,13 @@ namespace CppSharp.Generators.CLI foreach (var include in includes) WriteLine(include); - } - public void GenerateDeclarations() - { - GenerateNamespace(TranslationUnit); + PopBlock(); } private void GenerateNamespace(Namespace @namespace) { + PushBlock(CLIBlockKind.Namespace); foreach (var @class in @namespace.Classes) { if (@class.Ignore) @@ -116,6 +122,8 @@ namespace CppSharp.Generators.CLI foreach(var childNamespace in @namespace.Namespaces) GenerateNamespace(childNamespace); + + PopBlock(); } public void GenerateDeclarationCommon(Declaration decl) @@ -126,6 +134,7 @@ namespace CppSharp.Generators.CLI public void GenerateClass(Class @class) { + PushBlock(CLIBlockKind.Class); //GenerateDeclarationCommon(@class); // Output a default constructor that takes the native pointer. @@ -134,7 +143,7 @@ namespace CppSharp.Generators.CLI foreach (var method in @class.Methods) { - if (CheckIgnoreMethod(@class, method)) + if (Utils.CheckIgnoreMethod(@class, method)) continue; GenerateDeclarationCommon(method); @@ -147,7 +156,7 @@ namespace CppSharp.Generators.CLI { foreach (var field in @class.Fields) { - if (CheckIgnoreField(@class, field)) + if (Utils.CheckIgnoreField(@class, field)) continue; GenerateFieldProperty(field); @@ -188,6 +197,8 @@ namespace CppSharp.Generators.CLI GenerateDeclarationCommon(variable); GenerateVariable(variable, @class); } + + PopBlock(); } private void GenerateFunctionTemplate(FunctionTemplate template, Class @class) @@ -471,7 +482,7 @@ namespace CppSharp.Generators.CLI foreach (var field in @class.Fields) { - if (CheckIgnoreField(@class, field)) continue; + if (Utils.CheckIgnoreField(@class, field)) continue; var nativeField = string.Format("{0}{1}", nativeVar, field.OriginalName); @@ -601,7 +612,7 @@ namespace CppSharp.Generators.CLI foreach (var field in @class.Fields) { - if (CheckIgnoreField(@class, field)) continue; + if (Utils.CheckIgnoreField(@class, field)) continue; var varName = string.Format("_native.{0}", field.OriginalName); diff --git a/src/Generator/Generators/CLI/CLITextTemplate.cs b/src/Generator/Generators/CLI/CLITextTemplate.cs index 17d05c08..63336bf7 100644 --- a/src/Generator/Generators/CLI/CLITextTemplate.cs +++ b/src/Generator/Generators/CLI/CLITextTemplate.cs @@ -21,12 +21,49 @@ namespace CppSharp.Generators.CLI } } + public enum CLIBlockKind + { + Unknown, + Header, + Includes, + IncludesForwardReferences, + Namespace, + ForwardReferences, + Footer, + Enum, + Typedef, + Class, + Method, + Usings + } + + public class CLIBlock : IBlock + { + public CLIBlockKind Kind { get; set; } + public List Blocks { get; set; } + public CLIBlock Parent { get; set; } + + public TextGenerator Text { get; set; } + public Declaration Declaration { get; set; } + + public CLIBlock() + { + Blocks = new List(); + Kind = CLIBlockKind.Unknown; + } + + public override string ToString() + { + return Kind.ToString(); + } + } + /// /// There are two implementation /// for source (CLISourcesTemplate) and header (CLIHeadersTemplate) /// files. /// - public abstract class CLITextTemplate : TextTemplate + public abstract class CLITextTemplate : BlockGenerator { public CLITypePrinter TypePrinter { get; set; } @@ -41,7 +78,7 @@ namespace CppSharp.Generators.CLI public abstract override string FileExtension { get; } - public abstract override void Generate(); + public abstract override void GenerateBlocks(); #region Helpers diff --git a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs index 8eb4043b..1a3ab879 100644 --- a/src/Generator/Generators/CSharp/CSharpTextTemplate.cs +++ b/src/Generator/Generators/CSharp/CSharpTextTemplate.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.IO; using System.Linq; using CppSharp.AST; +using CppSharp.Passes; namespace CppSharp.Generators.CSharp { @@ -111,7 +112,7 @@ namespace CppSharp.Generators.CSharp #endregion - public override void Generate() + public override void GenerateBlocks() { GenerateHeader(); @@ -134,12 +135,6 @@ namespace CppSharp.Generators.CSharp public void GenerateHeader() { - if (Transform != null) - { - //Transform.GenerateStart(this); - return; - } - WriteLine("//----------------------------------------------------------------------------"); WriteLine("// This is autogenerated code by CppSharp."); WriteLine("// Do not edit this file or all your changes will be lost after re-generation."); diff --git a/src/Generator/Generators/Template.cs b/src/Generator/Generators/Template.cs index 3cee968a..87f41954 100644 --- a/src/Generator/Generators/Template.cs +++ b/src/Generator/Generators/Template.cs @@ -20,7 +20,7 @@ namespace CppSharp.Generators public abstract string FileExtension { get; } - public abstract void Generate(); + public abstract void GenerateBlocks(); public virtual string GenerateText() { @@ -28,4 +28,94 @@ namespace CppSharp.Generators } } + /// + /// Represents a (nestable) block of text with a specific kind. + /// + public interface IBlock + { + TKind Kind { get; set; } + List Blocks { get; set; } + TBlock Parent { get; set; } + + TextGenerator Text { get; set; } + Declaration Declaration { get; set; } + } + + /// + /// Block generator used by language-specific generators to generate + /// their output. + /// + public abstract class BlockGenerator : TextTemplate + where TBlock : IBlock, new() + { + public struct BlockData + { + public TBlock Block; + public int StartPosition; + } + + public List Blocks { get; private set; } + protected readonly Stack CurrentBlocks; + + protected BlockGenerator(Driver driver, TranslationUnit unit) + : base(driver, unit) + { + Blocks = new List(); + CurrentBlocks = new Stack(); + } + + public void PushBlock(TKind kind) + { + var data = new BlockData + { + Block = new TBlock { Kind = kind }, + StartPosition = StringBuilder.Length + }; + + CurrentBlocks.Push(data); + } + + public void PopBlock() + { + var data = CurrentBlocks.Pop(); + var block = data.Block; + + var text = StringBuilder.ToString().Substring(data.StartPosition); + block.Text = Clone(); + block.Text.StringBuilder = new StringBuilder(text); + + var hasParentBlock = CurrentBlocks.Count > 0; + if (hasParentBlock) + CurrentBlocks.Peek().Block.Blocks.Add(block); + else + Blocks.Add(block); + } + + public TBlock FindBlock(TKind kind) + { + //foreach (var block in Blocks) + // if (block.Kind == kind) + // return block; + return default(TBlock); + } + + public override string GenerateText() + { + var generator = new TextGenerator(); + + foreach (var block in Blocks) + GenerateBlock(block, generator); + + return generator.ToString(); + } + + void GenerateBlock(TBlock block, TextGenerator gen) + { + if (block.Blocks.Count == 0) + gen.Write(block.Text); + + foreach (var childBlock in block.Blocks) + GenerateBlock(childBlock, gen); + } + } } \ No newline at end of file