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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -155,6 +169,7 @@ namespace CppSharp.Generators.CLI
if (generateNamespace)
{
WriteCloseBraceIndent();
PopBlock();
}
}
@ -169,6 +184,7 @@ namespace CppSharp.Generators.CLI @@ -169,6 +184,7 @@ namespace CppSharp.Generators.CLI
continue;
NewLine();
PopBlock();
}
}
@ -532,11 +548,12 @@ namespace CppSharp.Generators.CLI @@ -532,11 +548,12 @@ namespace CppSharp.Generators.CLI
if (typedef.Ignore)
return false;
GenerateDeclarationCommon(typedef);
FunctionType function;
if (typedef.Type.IsPointerTo<FunctionType>(out function))
{
PushBlock(CLIBlockKind.Typedef);
GenerateDeclarationCommon(typedef);
WriteLine("public {0};",
string.Format(TypePrinter.VisitDelegate(function),
SafeIdentifier(typedef.Name)));

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

@ -3,6 +3,7 @@ using System.Collections.Generic; @@ -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 @@ -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 <clix.hpp>");
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<string>(StringComparer.InvariantCulture);
var typeRefs = TranslationUnit.TypeReferences as TypeRefsVisitor;
@ -81,15 +89,13 @@ namespace CppSharp.Generators.CLI @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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);

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

@ -21,12 +21,49 @@ namespace CppSharp.Generators.CLI @@ -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>
/// There are two implementation
/// for source (CLISourcesTemplate) and header (CLIHeadersTemplate)
/// files.
/// </summary>
public abstract class CLITextTemplate : TextTemplate
public abstract class CLITextTemplate : BlockGenerator<CLIBlockKind, CLIBlock>
{
public CLITypePrinter TypePrinter { get; set; }
@ -41,7 +78,7 @@ namespace CppSharp.Generators.CLI @@ -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

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

@ -4,6 +4,7 @@ using System.Globalization; @@ -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 @@ -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 @@ -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.");

92
src/Generator/Generators/Template.cs

@ -20,7 +20,7 @@ namespace CppSharp.Generators @@ -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 @@ -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