Browse Source

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.
pull/12/merge
triton 13 years ago
parent
commit
6308cf4c3c
  1. 27
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  2. 41
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  3. 41
      src/Generator/Generators/CLI/CLITextTemplate.cs
  4. 9
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  5. 92
      src/Generator/Generators/Template.cs

27
src/Generator/Generators/CLI/CLIHeadersTemplate.cs

@ -17,22 +17,29 @@ namespace CppSharp.Generators.CLI
public CLIHeadersTemplate(Driver driver, TranslationUnit unit) public CLIHeadersTemplate(Driver driver, TranslationUnit unit)
: base(driver, unit) : base(driver, unit)
{ {
} }
public override void Generate() public override void GenerateBlocks()
{ {
OnStart(this); PushBlock(CLIBlockKind.Header);
PopBlock();
PushBlock(CLIBlockKind.Includes);
WriteLine("#pragma once"); WriteLine("#pragma once");
NewLine(); NewLine();
PushBlock(CLIBlockKind.IncludesForwardReferences);
WriteLine("#include <{0}>", TranslationUnit.IncludePath); WriteLine("#include <{0}>", TranslationUnit.IncludePath);
GenerateIncludeForwardRefs(); GenerateIncludeForwardRefs();
NewLine(); NewLine();
PopBlock();
PopBlock();
GenerateNamespace(TranslationUnit); GenerateNamespace(TranslationUnit);
PushBlock(CLIBlockKind.Footer);
PopBlock();
} }
public void GenerateIncludeForwardRefs() public void GenerateIncludeForwardRefs()
@ -96,6 +103,7 @@ namespace CppSharp.Generators.CLI
if (generateNamespace) if (generateNamespace)
{ {
PushBlock(CLIBlockKind.Namespace);
WriteLine("namespace {0}", isTopLevel WriteLine("namespace {0}", isTopLevel
? Options.OutputNamespace ? Options.OutputNamespace
: SafeIdentifier(@namespace.Name)); : SafeIdentifier(@namespace.Name));
@ -103,7 +111,9 @@ namespace CppSharp.Generators.CLI
} }
// Generate the forward references. // Generate the forward references.
PushBlock(CLIBlockKind.ForwardReferences);
GenerateForwardRefs(@namespace); GenerateForwardRefs(@namespace);
PopBlock();
// Generate all the enum declarations for the module. // Generate all the enum declarations for the module.
for (var i = 0; i < @namespace.Enums.Count; ++i) for (var i = 0; i < @namespace.Enums.Count; ++i)
@ -113,11 +123,13 @@ namespace CppSharp.Generators.CLI
if (@enum.Ignore || @enum.IsIncomplete) if (@enum.Ignore || @enum.IsIncomplete)
continue; continue;
PushBlock(CLIBlockKind.Enum);
GenerateEnum(@enum); GenerateEnum(@enum);
NeedNewLine(); NeedNewLine();
if (i < @namespace.Enums.Count - 1) if (i < @namespace.Enums.Count - 1)
NewLine(); NewLine();
PopBlock();
} }
NewLineIfNeeded(); NewLineIfNeeded();
@ -136,11 +148,13 @@ namespace CppSharp.Generators.CLI
if (@class.IsOpaque) if (@class.IsOpaque)
continue; continue;
PushBlock(CLIBlockKind.Class);
GenerateClass(@class); GenerateClass(@class);
NeedNewLine(); NeedNewLine();
if (i < @namespace.Classes.Count - 1) if (i < @namespace.Classes.Count - 1)
NewLine(); NewLine();
PopBlock();
} }
if (@namespace.HasFunctions) if (@namespace.HasFunctions)
@ -155,6 +169,7 @@ namespace CppSharp.Generators.CLI
if (generateNamespace) if (generateNamespace)
{ {
WriteCloseBraceIndent(); WriteCloseBraceIndent();
PopBlock();
} }
} }
@ -169,6 +184,7 @@ namespace CppSharp.Generators.CLI
continue; continue;
NewLine(); NewLine();
PopBlock();
} }
} }
@ -532,11 +548,12 @@ namespace CppSharp.Generators.CLI
if (typedef.Ignore) if (typedef.Ignore)
return false; return false;
GenerateDeclarationCommon(typedef);
FunctionType function; FunctionType function;
if (typedef.Type.IsPointerTo<FunctionType>(out function)) if (typedef.Type.IsPointerTo<FunctionType>(out function))
{ {
PushBlock(CLIBlockKind.Typedef);
GenerateDeclarationCommon(typedef);
WriteLine("public {0};", WriteLine("public {0};",
string.Format(TypePrinter.VisitDelegate(function), string.Format(TypePrinter.VisitDelegate(function),
SafeIdentifier(typedef.Name))); SafeIdentifier(typedef.Name)));

41
src/Generator/Generators/CLI/CLISourcesTemplate.cs

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using CppSharp.AST;
using CppSharp.Types; using CppSharp.Types;
namespace CppSharp.Generators.CLI 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) if (Driver.Options.GenerateName != null)
file = Driver.Options.GenerateName(TranslationUnit); file = Driver.Options.GenerateName(TranslationUnit);
PushBlock(CLIBlockKind.Includes);
WriteLine("#include \"{0}.h\"", file); WriteLine("#include \"{0}.h\"", file);
GenerateForwardReferenceHeaders(); GenerateForwardReferenceHeaders();
if (Options.OutputInteropIncludes) if (Options.OutputInteropIncludes)
WriteLine("#include <clix.hpp>"); WriteLine("#include <clix.hpp>");
NewLine(); NewLine();
PopBlock();
PushBlock(CLIBlockKind.Usings);
WriteLine("using namespace System;"); WriteLine("using namespace System;");
WriteLine("using namespace System::Runtime::InteropServices;"); WriteLine("using namespace System::Runtime::InteropServices;");
OnNamespaces(this);
NewLine(); NewLine();
PopBlock();
GenerateDeclarations(); GenerateNamespace(TranslationUnit);
PushBlock(CLIBlockKind.Footer);
PopBlock();
} }
public void GenerateForwardReferenceHeaders() public void GenerateForwardReferenceHeaders()
{ {
PushBlock(CLIBlockKind.IncludesForwardReferences);
var includes = new SortedSet<string>(StringComparer.InvariantCulture); var includes = new SortedSet<string>(StringComparer.InvariantCulture);
var typeRefs = TranslationUnit.TypeReferences as TypeRefsVisitor; var typeRefs = TranslationUnit.TypeReferences as TypeRefsVisitor;
@ -81,15 +89,13 @@ namespace CppSharp.Generators.CLI
foreach (var include in includes) foreach (var include in includes)
WriteLine(include); WriteLine(include);
}
public void GenerateDeclarations() PopBlock();
{
GenerateNamespace(TranslationUnit);
} }
private void GenerateNamespace(Namespace @namespace) private void GenerateNamespace(Namespace @namespace)
{ {
PushBlock(CLIBlockKind.Namespace);
foreach (var @class in @namespace.Classes) foreach (var @class in @namespace.Classes)
{ {
if (@class.Ignore) if (@class.Ignore)
@ -116,6 +122,8 @@ namespace CppSharp.Generators.CLI
foreach(var childNamespace in @namespace.Namespaces) foreach(var childNamespace in @namespace.Namespaces)
GenerateNamespace(childNamespace); GenerateNamespace(childNamespace);
PopBlock();
} }
public void GenerateDeclarationCommon(Declaration decl) public void GenerateDeclarationCommon(Declaration decl)
@ -126,6 +134,7 @@ namespace CppSharp.Generators.CLI
public void GenerateClass(Class @class) public void GenerateClass(Class @class)
{ {
PushBlock(CLIBlockKind.Class);
//GenerateDeclarationCommon(@class); //GenerateDeclarationCommon(@class);
// Output a default constructor that takes the native pointer. // Output a default constructor that takes the native pointer.
@ -134,7 +143,7 @@ namespace CppSharp.Generators.CLI
foreach (var method in @class.Methods) foreach (var method in @class.Methods)
{ {
if (CheckIgnoreMethod(@class, method)) if (Utils.CheckIgnoreMethod(@class, method))
continue; continue;
GenerateDeclarationCommon(method); GenerateDeclarationCommon(method);
@ -147,7 +156,7 @@ namespace CppSharp.Generators.CLI
{ {
foreach (var field in @class.Fields) foreach (var field in @class.Fields)
{ {
if (CheckIgnoreField(@class, field)) if (Utils.CheckIgnoreField(@class, field))
continue; continue;
GenerateFieldProperty(field); GenerateFieldProperty(field);
@ -188,6 +197,8 @@ namespace CppSharp.Generators.CLI
GenerateDeclarationCommon(variable); GenerateDeclarationCommon(variable);
GenerateVariable(variable, @class); GenerateVariable(variable, @class);
} }
PopBlock();
} }
private void GenerateFunctionTemplate(FunctionTemplate template, Class @class) private void GenerateFunctionTemplate(FunctionTemplate template, Class @class)
@ -471,7 +482,7 @@ namespace CppSharp.Generators.CLI
foreach (var field in @class.Fields) foreach (var field in @class.Fields)
{ {
if (CheckIgnoreField(@class, field)) continue; if (Utils.CheckIgnoreField(@class, field)) continue;
var nativeField = string.Format("{0}{1}", var nativeField = string.Format("{0}{1}",
nativeVar, field.OriginalName); nativeVar, field.OriginalName);
@ -601,7 +612,7 @@ namespace CppSharp.Generators.CLI
foreach (var field in @class.Fields) 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); var varName = string.Format("_native.{0}", field.OriginalName);

41
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<CLIBlock, CLIBlockKind>
{
public CLIBlockKind Kind { get; set; }
public List<CLIBlock> Blocks { get; set; }
public CLIBlock Parent { get; set; }
public TextGenerator Text { get; set; }
public Declaration Declaration { get; set; }
public CLIBlock()
{
Blocks = new List<CLIBlock>();
Kind = CLIBlockKind.Unknown;
}
public override string ToString()
{
return Kind.ToString();
}
}
/// <summary> /// <summary>
/// There are two implementation /// There are two implementation
/// for source (CLISourcesTemplate) and header (CLIHeadersTemplate) /// for source (CLISourcesTemplate) and header (CLIHeadersTemplate)
/// files. /// files.
/// </summary> /// </summary>
public abstract class CLITextTemplate : TextTemplate public abstract class CLITextTemplate : BlockGenerator<CLIBlockKind, CLIBlock>
{ {
public CLITypePrinter TypePrinter { get; set; } public CLITypePrinter TypePrinter { get; set; }
@ -41,7 +78,7 @@ namespace CppSharp.Generators.CLI
public abstract override string FileExtension { get; } public abstract override string FileExtension { get; }
public abstract override void Generate(); public abstract override void GenerateBlocks();
#region Helpers #region Helpers

9
src/Generator/Generators/CSharp/CSharpTextTemplate.cs

@ -4,6 +4,7 @@ using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using CppSharp.AST; using CppSharp.AST;
using CppSharp.Passes;
namespace CppSharp.Generators.CSharp namespace CppSharp.Generators.CSharp
{ {
@ -111,7 +112,7 @@ namespace CppSharp.Generators.CSharp
#endregion #endregion
public override void Generate() public override void GenerateBlocks()
{ {
GenerateHeader(); GenerateHeader();
@ -134,12 +135,6 @@ namespace CppSharp.Generators.CSharp
public void GenerateHeader() public void GenerateHeader()
{ {
if (Transform != null)
{
//Transform.GenerateStart(this);
return;
}
WriteLine("//----------------------------------------------------------------------------"); WriteLine("//----------------------------------------------------------------------------");
WriteLine("// This is autogenerated code by CppSharp."); WriteLine("// This is autogenerated code by CppSharp.");
WriteLine("// Do not edit this file or all your changes will be lost after re-generation."); WriteLine("// Do not edit this file or all your changes will be lost after re-generation.");

92
src/Generator/Generators/Template.cs

@ -20,7 +20,7 @@ namespace CppSharp.Generators
public abstract string FileExtension { get; } public abstract string FileExtension { get; }
public abstract void Generate(); public abstract void GenerateBlocks();
public virtual string GenerateText() public virtual string GenerateText()
{ {
@ -28,4 +28,94 @@ namespace CppSharp.Generators
} }
} }
/// <summary>
/// Represents a (nestable) block of text with a specific kind.
/// </summary>
public interface IBlock<TBlock, TKind>
{
TKind Kind { get; set; }
List<TBlock> Blocks { get; set; }
TBlock Parent { get; set; }
TextGenerator Text { get; set; }
Declaration Declaration { get; set; }
}
/// <summary>
/// Block generator used by language-specific generators to generate
/// their output.
/// </summary>
public abstract class BlockGenerator<TKind, TBlock> : TextTemplate
where TBlock : IBlock<TBlock, TKind>, new()
{
public struct BlockData
{
public TBlock Block;
public int StartPosition;
}
public List<TBlock> Blocks { get; private set; }
protected readonly Stack<BlockData> CurrentBlocks;
protected BlockGenerator(Driver driver, TranslationUnit unit)
: base(driver, unit)
{
Blocks = new List<TBlock>();
CurrentBlocks = new Stack<BlockData>();
}
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);
}
}
} }
Loading…
Cancel
Save