Browse Source

Re-write the blocks generator again (thanks to esdrubal for helping me with the new design).

Now the whitespace/new line handling is done by the output generator per block, instead of having to be managed manually which could lead to all sorts of messy output without being extra careful.

Also the new system limits the usage of generics since C# was too limited to design it properly, and it ended up being more trouble than it was worth. The blocks kinds were also changed to be const int, since enums are very hard to extend and made it hard to provide a common interface for dealing with blocks.
pull/13/merge
triton 12 years ago
parent
commit
b9e57dba78
  1. 9
      src/Generator/Driver.cs
  2. 4
      src/Generator/Generators/CLI/CLIGenerator.cs
  3. 81
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  4. 16
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  5. 64
      src/Generator/Generators/CLI/CLITextTemplate.cs
  6. 4
      src/Generator/Generators/CSharp/CSharpGenerator.cs
  7. 13
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  8. 6
      src/Generator/Generators/Generator.cs
  9. 350
      src/Generator/Generators/Template.cs
  10. 25
      src/Generator/Utils/TextGenerator.cs

9
src/Generator/Driver.cs

@ -122,8 +122,7 @@ namespace CppSharp @@ -122,8 +122,7 @@ namespace CppSharp
public List<GeneratorOutput> GenerateCode()
{
var outputs = Generator.Generate();
return outputs;
return Generator.Generate();
}
public void WriteCode(List<GeneratorOutput> outputs)
@ -146,9 +145,7 @@ namespace CppSharp @@ -146,9 +145,7 @@ namespace CppSharp
Diagnostics.EmitMessage(DiagnosticId.FileGenerated, "Generated '{0}'", fileName);
var filePath = Path.Combine(outputPath, fileName);
var text = template.GenerateText();
File.WriteAllText(Path.GetFullPath(filePath), text);
File.WriteAllText(Path.GetFullPath(filePath), template.Generate());
}
}
}
@ -177,6 +174,7 @@ namespace CppSharp @@ -177,6 +174,7 @@ namespace CppSharp
GeneratePartialClasses = true;
OutputInteropIncludes = true;
MaxIndent = 80;
CommentPrefix = "///";
}
// General options
@ -218,6 +216,7 @@ namespace CppSharp @@ -218,6 +216,7 @@ namespace CppSharp
public bool WriteOnlyWhenChanged;
public Func<TranslationUnit, string> GenerateName;
public int MaxIndent;
public string CommentPrefix;
}
public class InvalidOptionException : Exception

4
src/Generator/Generators/CLI/CLIGenerator.cs

@ -17,9 +17,9 @@ namespace CppSharp.Generators.CLI @@ -17,9 +17,9 @@ namespace CppSharp.Generators.CLI
Type.TypePrinterDelegate += type => type.Visit(typePrinter);
}
public override List<TextTemplate> Generate(TranslationUnit unit)
public override List<Template> Generate(TranslationUnit unit)
{
var outputs = new List<TextTemplate>();
var outputs = new List<Template>();
var header = new CLIHeadersTemplate(Driver, unit);
outputs.Add(header);

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

@ -19,9 +19,9 @@ namespace CppSharp.Generators.CLI @@ -19,9 +19,9 @@ namespace CppSharp.Generators.CLI
{
}
public override void GenerateBlocks()
public override void Process()
{
PushBlock(CLIBlockKind.Header);
PushBlock(BlockKind.Header);
PopBlock();
PushBlock(CLIBlockKind.Includes);
@ -31,14 +31,13 @@ namespace CppSharp.Generators.CLI @@ -31,14 +31,13 @@ namespace CppSharp.Generators.CLI
PushBlock(CLIBlockKind.IncludesForwardReferences);
WriteLine("#include <{0}>", TranslationUnit.IncludePath);
GenerateIncludeForwardRefs();
PopBlock(NewLineKind.BeforeNextBlock);
NewLine();
PopBlock();
PopBlock();
PopBlock(NewLineKind.Always);
GenerateNamespace(TranslationUnit);
PushBlock(CLIBlockKind.Footer);
PushBlock(BlockKind.Footer);
PopBlock();
}
@ -88,14 +87,9 @@ namespace CppSharp.Generators.CLI @@ -88,14 +87,9 @@ namespace CppSharp.Generators.CLI
}
foreach (var forwardRef in forwardRefs)
{
WriteLine(forwardRef);
}
if (forwardRefs.Count > 0)
NewLine();
}
public void GenerateNamespace(Namespace @namespace)
{
var isTopLevel = @namespace is TranslationUnit;
@ -103,7 +97,7 @@ namespace CppSharp.Generators.CLI @@ -103,7 +97,7 @@ namespace CppSharp.Generators.CLI
if (generateNamespace)
{
PushBlock(CLIBlockKind.Namespace);
PushBlock(CLIBlockKind.Namespace, @namespace);
WriteLine("namespace {0}", isTopLevel
? Options.OutputNamespace
: SafeIdentifier(@namespace.Name));
@ -113,55 +107,38 @@ namespace CppSharp.Generators.CLI @@ -113,55 +107,38 @@ namespace CppSharp.Generators.CLI
// Generate the forward references.
PushBlock(CLIBlockKind.ForwardReferences);
GenerateForwardRefs(@namespace);
PopBlock();
PopBlock(NewLineKind.BeforeNextBlock);
// Generate all the enum declarations for the module.
for (var i = 0; i < @namespace.Enums.Count; ++i)
foreach (var @enum in @namespace.Enums)
{
var @enum = @namespace.Enums[i];
if (@enum.Ignore || @enum.IsIncomplete)
continue;
PushBlock(CLIBlockKind.Enum);
PushBlock(CLIBlockKind.Enum, @enum);
GenerateEnum(@enum);
NeedNewLine();
if (i < @namespace.Enums.Count - 1)
NewLine();
PopBlock();
PopBlock(NewLineKind.BeforeNextBlock);
}
NewLineIfNeeded();
// Generate all the typedef declarations for the module.
GenerateTypedefs(@namespace);
// Generate all the struct/class declarations for the module.
for (var i = 0; i < @namespace.Classes.Count; ++i)
foreach (var @class in @namespace.Classes)
{
var @class = @namespace.Classes[i];
if (@class.Ignore || @class.IsIncomplete)
continue;
if (@class.IsOpaque)
continue;
PushBlock(CLIBlockKind.Class);
PushBlock(CLIBlockKind.Class, @class);
GenerateClass(@class);
NeedNewLine();
if (i < @namespace.Classes.Count - 1)
NewLine();
PopBlock();
PopBlock(NewLineKind.BeforeNextBlock);
}
if (@namespace.HasFunctions)
{
NewLineIfNeeded();
GenerateFunctions(@namespace);
}
foreach(var childNamespace in @namespace.Namespaces)
GenerateNamespace(childNamespace);
@ -169,7 +146,7 @@ namespace CppSharp.Generators.CLI @@ -169,7 +146,7 @@ namespace CppSharp.Generators.CLI
if (generateNamespace)
{
WriteCloseBraceIndent();
PopBlock();
PopBlock(NewLineKind.BeforeNextBlock);
}
}
@ -180,16 +157,14 @@ namespace CppSharp.Generators.CLI @@ -180,16 +157,14 @@ namespace CppSharp.Generators.CLI
if (typedef.Ignore)
continue;
if (!GenerateTypedef(typedef))
continue;
NewLine();
PopBlock();
GenerateTypedef(typedef);
}
}
public void GenerateFunctions(Namespace @namespace)
{
PushBlock(CLIBlockKind.FunctionsClass);
WriteLine("public ref class {0}{1}", SafeIdentifier(Options.OutputNamespace),
TranslationUnit.FileNameWithoutExtension);
WriteLine("{");
@ -204,6 +179,8 @@ namespace CppSharp.Generators.CLI @@ -204,6 +179,8 @@ namespace CppSharp.Generators.CLI
PopIndent();
WriteLine("};");
PopBlock(NewLineKind.BeforeNextBlock);
}
public void GenerateDeclarationCommon(Declaration T)
@ -376,7 +353,6 @@ namespace CppSharp.Generators.CLI @@ -376,7 +353,6 @@ namespace CppSharp.Generators.CLI
public void GenerateClassEvents(Class @class)
{
PushIndent();
foreach (var @event in @class.Events)
{
if (@event.Ignore) continue;
@ -384,7 +360,6 @@ namespace CppSharp.Generators.CLI @@ -384,7 +360,6 @@ namespace CppSharp.Generators.CLI
var cppTypePrinter = new CppTypePrinter(Driver.TypeDatabase);
var cppArgs = cppTypePrinter.VisitParameters(@event.Parameters, hasNames: true);
PopIndent();
WriteLine("private:");
PushIndent();
@ -410,9 +385,9 @@ namespace CppSharp.Generators.CLI @@ -410,9 +385,9 @@ namespace CppSharp.Generators.CLI
WriteLine("void raise({0});", cliArgs);
WriteCloseBraceIndent();
}
PopIndent();
}
}
public void GenerateClassMethods(Class @class)
{
@ -528,6 +503,8 @@ namespace CppSharp.Generators.CLI @@ -528,6 +503,8 @@ namespace CppSharp.Generators.CLI
if (method.Access != AccessSpecifier.Public)
return;
PushBlock(CLIBlockKind.Method, method);
GenerateDeclarationCommon(method);
if (method.IsStatic)
@ -541,6 +518,8 @@ namespace CppSharp.Generators.CLI @@ -541,6 +518,8 @@ namespace CppSharp.Generators.CLI
GenerateMethodParameters(method);
WriteLine(");");
PopBlock();
}
public bool GenerateTypedef(TypedefDecl typedef)
@ -551,12 +530,14 @@ namespace CppSharp.Generators.CLI @@ -551,12 +530,14 @@ namespace CppSharp.Generators.CLI
FunctionType function;
if (typedef.Type.IsPointerTo<FunctionType>(out function))
{
PushBlock(CLIBlockKind.Typedef);
PushBlock(CLIBlockKind.Typedef, typedef);
GenerateDeclarationCommon(typedef);
WriteLine("public {0};",
string.Format(TypePrinter.VisitDelegate(function),
SafeIdentifier(typedef.Name)));
PopBlock(NewLineKind.BeforeNextBlock);
return true;
}
else if (typedef.Type.IsEnumType())
@ -573,7 +554,11 @@ namespace CppSharp.Generators.CLI @@ -573,7 +554,11 @@ namespace CppSharp.Generators.CLI
public void GenerateFunction(Function function)
{
if (function.Ignore) return;
if (function.Ignore)
return;
PushBlock(CLIBlockKind.Function, function);
GenerateDeclarationCommon(function);
var retType = function.ReturnType.ToString();
@ -582,6 +567,8 @@ namespace CppSharp.Generators.CLI @@ -582,6 +567,8 @@ namespace CppSharp.Generators.CLI
Write(GenerateParametersList(function.Parameters));
WriteLine(");");
PopBlock();
}
public void GenerateDebug(Declaration decl)

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

@ -19,9 +19,9 @@ namespace CppSharp.Generators.CLI @@ -19,9 +19,9 @@ namespace CppSharp.Generators.CLI
}
public override void GenerateBlocks()
public override void Process()
{
PushBlock(CLIBlockKind.Header);
PushBlock(BlockKind.Header);
PopBlock();
var file = Path.GetFileNameWithoutExtension(TranslationUnit.FileName)
@ -48,7 +48,7 @@ namespace CppSharp.Generators.CLI @@ -48,7 +48,7 @@ namespace CppSharp.Generators.CLI
GenerateNamespace(TranslationUnit);
PushBlock(CLIBlockKind.Footer);
PushBlock(BlockKind.Footer);
PopBlock();
}
@ -78,7 +78,7 @@ namespace CppSharp.Generators.CLI @@ -78,7 +78,7 @@ namespace CppSharp.Generators.CLI
var includeName = Path.GetFileNameWithoutExtension(translationUnit.FileName);
if (includeName == Path.GetFileNameWithoutExtension(((TextTemplate) this).TranslationUnit.FileName))
if (includeName == Path.GetFileNameWithoutExtension(TranslationUnit.FileName))
continue;
includes.Add(string.Format("#include \"{0}.h\"", includeName.Replace('\\', '/')));
@ -544,6 +544,11 @@ namespace CppSharp.Generators.CLI @@ -544,6 +544,11 @@ namespace CppSharp.Generators.CLI
WriteStartBraceIndent();
PushBlock(CLIBlockKind.MethodBody, method);
if (method.IsProxy)
goto SkipImpl;
if (@class.IsRefType)
{
if (method.Kind == CXXMethodKind.Constructor)
@ -569,6 +574,9 @@ namespace CppSharp.Generators.CLI @@ -569,6 +574,9 @@ namespace CppSharp.Generators.CLI
GenerateValueTypeConstructorCall(method, @class);
}
SkipImpl:
PopBlock();
WriteCloseBraceIndent();
}

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

@ -1,5 +1,6 @@ @@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using CppSharp.AST;
namespace CppSharp.Generators.CLI
@ -22,41 +23,20 @@ namespace CppSharp.Generators.CLI @@ -22,41 +23,20 @@ namespace CppSharp.Generators.CLI
}
}
public enum CLIBlockKind
public class 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();
}
public const int Includes = BlockKind.LAST + 1;
public const int IncludesForwardReferences = BlockKind.LAST + 2;
public const int Namespace = BlockKind.LAST + 3;
public const int ForwardReferences = BlockKind.LAST + 4;
public const int Enum = BlockKind.LAST + 5;
public const int Typedef = BlockKind.LAST + 6;
public const int Class = BlockKind.LAST + 7;
public const int Method = BlockKind.LAST + 8;
public const int MethodBody = BlockKind.LAST + 9;
public const int Usings = BlockKind.LAST + 10;
public const int FunctionsClass = BlockKind.LAST + 11;
public const int Function = BlockKind.LAST + 12;
}
/// <summary>
@ -64,7 +44,7 @@ namespace CppSharp.Generators.CLI @@ -64,7 +44,7 @@ namespace CppSharp.Generators.CLI
/// for source (CLISourcesTemplate) and header (CLIHeadersTemplate)
/// files.
/// </summary>
public abstract class CLITextTemplate : BlockGenerator<CLIBlockKind, CLIBlock>
public abstract class CLITextTemplate : Template
{
public CLITypePrinter TypePrinter { get; set; }
@ -79,7 +59,7 @@ namespace CppSharp.Generators.CLI @@ -79,7 +59,7 @@ namespace CppSharp.Generators.CLI
public abstract override string FileExtension { get; }
public abstract override void GenerateBlocks();
public abstract override void Process();
#region Helpers
@ -100,21 +80,21 @@ namespace CppSharp.Generators.CLI @@ -100,21 +80,21 @@ namespace CppSharp.Generators.CLI
if (string.IsNullOrWhiteSpace(comment))
return;
// Wrap the comment to the line width.
var maxSize = (int)(Options.MaxIndent - CurrentIndent.Count - "/// ".Length);
var lines = StringHelpers.WordWrapLines(comment, maxSize);
PushBlock(BlockKind.BlockComment);
WriteLine("/// <summary>");
foreach (string line in lines)
WriteLine(string.Format("/// {0}", line.TrimEnd()));
WriteLine(comment);
WriteLine("/// </summary>");
PopBlock();
}
public void GenerateInlineSummary(string comment)
{
if (String.IsNullOrWhiteSpace(comment))
return;
PushBlock(BlockKind.InlineComment);
WriteLine("/// <summary> {0} </summary>", comment);
PopBlock();
}
public void GenerateMethodParameters(Method method)

4
src/Generator/Generators/CSharp/CSharpGenerator.cs

@ -16,9 +16,9 @@ namespace CppSharp.Generators.CSharp @@ -16,9 +16,9 @@ namespace CppSharp.Generators.CSharp
AST.Type.TypePrinterDelegate += type => type.Visit(typePrinter).Type;
}
public override List<TextTemplate> Generate(TranslationUnit unit)
public override List<Template> Generate(TranslationUnit unit)
{
var outputs = new List<TextTemplate>();
var outputs = new List<Template>();
var template = new CSharpTextTemplate(Driver, unit, typePrinter);
outputs.Add(template);

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

@ -63,7 +63,12 @@ namespace CppSharp.Generators.CSharp @@ -63,7 +63,12 @@ namespace CppSharp.Generators.CSharp
}
}
public class CSharpTextTemplate : TextTemplate
public class CSharpBlockKind
{
}
public class CSharpTextTemplate : Template
{
public CSharpTypePrinter TypePrinter { get; private set; }
@ -112,7 +117,7 @@ namespace CppSharp.Generators.CSharp @@ -112,7 +117,7 @@ namespace CppSharp.Generators.CSharp
#endregion
public override void GenerateBlocks()
public override void Process()
{
GenerateHeader();
@ -259,9 +264,11 @@ namespace CppSharp.Generators.CSharp @@ -259,9 +264,11 @@ namespace CppSharp.Generators.CSharp
if (String.IsNullOrWhiteSpace(comment))
return;
PushBlock(BlockKind.BlockComment);
WriteLine("/// <summary>");
WriteLine("/// {0}", comment);
WriteLine("/// </summary>");
PopBlock();
}
public void GenerateInlineSummary(string comment)
@ -269,7 +276,9 @@ namespace CppSharp.Generators.CSharp @@ -269,7 +276,9 @@ namespace CppSharp.Generators.CSharp
if (String.IsNullOrWhiteSpace(comment))
return;
PushBlock(BlockKind.InlineComment);
WriteLine("/// <summary>{0}</summary>", comment);
PopBlock();
}
#region Classes

6
src/Generator/Generators/Generator.cs

@ -26,7 +26,7 @@ namespace CppSharp.Generators @@ -26,7 +26,7 @@ namespace CppSharp.Generators
/// <summary>
/// Text templates with generated output.
/// </summary>
public List<TextTemplate> Templates;
public List<Template> Templates;
}
/// <summary>
@ -79,7 +79,7 @@ namespace CppSharp.Generators @@ -79,7 +79,7 @@ namespace CppSharp.Generators
continue;
foreach (var template in templates)
template.GenerateBlocks();
template.Process();
var output = new GeneratorOutput
{
@ -97,6 +97,6 @@ namespace CppSharp.Generators @@ -97,6 +97,6 @@ namespace CppSharp.Generators
/// <summary>
/// Generates the outputs for a given translation unit.
/// </summary>
public abstract List<TextTemplate> Generate(TranslationUnit unit);
public abstract List<Template> Generate(TranslationUnit unit);
}
}

350
src/Generator/Generators/Template.cs

@ -1,122 +1,340 @@ @@ -1,122 +1,340 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CppSharp.AST;
namespace CppSharp.Generators
{
public abstract class TextTemplate : TextGenerator
public enum NewLineKind
{
Never,
Always,
BeforeNextBlock
}
public class BlockKind
{
public const int Unknown = 0;
public const int BlockComment = 1;
public const int InlineComment = 2;
public const int Header = 3;
public const int Footer = 4;
public const int LAST = 5;
}
public class Block : ITextGenerator
{
public TextGenerator Text { get; set; }
public int Kind { get; set; }
public NewLineKind NewLineKind { get; set; }
public Block Parent { get; set; }
private List<Block> Blocks { get; set; }
public Declaration Declaration { get; set; }
private bool hasIndentChanged;
private bool isSubBlock;
public Block() : this(BlockKind.Unknown)
{
}
public Block(int kind)
{
Kind = kind;
Blocks = new List<Block>();
Text = new TextGenerator();
hasIndentChanged = false;
isSubBlock = false;
}
public void AddBlock(Block block)
{
if (Text.StringBuilder.Length != 0 || hasIndentChanged)
{
hasIndentChanged = false;
var newBlock = new Block { Text = Text.Clone(), isSubBlock = true };
Text.StringBuilder.Clear();
AddBlock(newBlock);
}
block.Parent = this;
Blocks.Add(block);
}
public IEnumerable<Block> FindBlocks(int kind)
{
foreach (var block in Blocks)
{
if (block.Kind == kind)
yield return block;
foreach (var childBlock in block.FindBlocks(kind))
yield return childBlock;
}
}
public virtual string Generate(DriverOptions options)
{
if (Blocks.Count == 0)
return Text.ToString();
var builder = new StringBuilder();
uint totalIndent = 0;
Block previousBlock = null;
foreach (var childBlock in Blocks)
{
var childText = childBlock.Generate(options);
if (string.IsNullOrEmpty(childText))
continue;
var lines = childText.SplitAndKeep(Environment.NewLine).ToList();
if (previousBlock != null &&
previousBlock.NewLineKind == NewLineKind.BeforeNextBlock)
builder.AppendLine();
if (childBlock.isSubBlock)
totalIndent = 0;
if (childBlock.Kind == BlockKind.BlockComment)
{
// Wrap the comment to the max line width.
var maxSize = options.MaxIndent - totalIndent;
maxSize -= options.CommentPrefix.Length + 2;
lines = StringHelpers.WordWrapLines(childText, (int)maxSize);
for (var i = 0; i < lines.Count; ++i)
{
var line = lines[i];
if (!line.StartsWith(options.CommentPrefix))
lines[i] = options.CommentPrefix + " " + line;
}
}
foreach (var line in lines)
{
if (string.IsNullOrEmpty(line))
continue;
if (!string.IsNullOrWhiteSpace(line))
builder.Append(new string(' ', (int)totalIndent));
builder.Append(line);
if (!line.EndsWith(Environment.NewLine))
builder.AppendLine();
}
if (childBlock.NewLineKind == NewLineKind.Always)
builder.AppendLine();
totalIndent += childBlock.Text.Indent;
previousBlock = childBlock;
}
if (Text.StringBuilder.Length != 0)
builder.Append(Text.StringBuilder);
return builder.ToString();
}
#region ITextGenerator implementation
public uint Indent { get { return Text.Indent; } }
public void Write(string msg, params object[] args)
{
Text.Write(msg, args);
}
public void WriteLine(string msg, params object[] args)
{
Text.WriteLine(msg, args);
}
public void WriteLineIndent(string msg, params object[] args)
{
Text.WriteLineIndent(msg, args);
}
public void NewLine()
{
Text.NewLine();
}
public void NewLineIfNeeded()
{
Text.NewLineIfNeeded();
}
public void NeedNewLine()
{
Text.NeedNewLine();
}
public void ResetNewLine()
{
Text.ResetNewLine();
}
public void PushIndent(uint indent = 4u)
{
hasIndentChanged = true;
Text.PushIndent(indent);
}
public void PopIndent()
{
hasIndentChanged = true;
Text.PopIndent();
}
public void WriteStartBraceIndent()
{
Text.WriteStartBraceIndent();
}
public void WriteCloseBraceIndent()
{
Text.WriteCloseBraceIndent();
}
#endregion
}
public abstract class Template : ITextGenerator
{
public Driver Driver { get; private set; }
public DriverOptions Options { get; private set; }
public Library Library { get; private set; }
public TranslationUnit TranslationUnit { get; private set; }
protected TextTemplate(Driver driver, TranslationUnit unit)
public Block RootBlock { get; private set; }
public Block ActiveBlock { get; private set; }
public abstract string FileExtension { get; }
protected Template(Driver driver, TranslationUnit unit)
{
Driver = driver;
Options = driver.Options;
Library = driver.Library;
TranslationUnit = unit;
RootBlock = new Block();
ActiveBlock = RootBlock;
}
public abstract string FileExtension { get; }
public abstract void Process();
public string Generate()
{
return RootBlock.Generate(Options);
}
public abstract void GenerateBlocks();
#region Block helpers
public virtual string GenerateText()
public void AddBlock(Block block)
{
return base.ToString();
ActiveBlock.AddBlock(block);
}
public void PushBlock(int kind, Declaration decl = null)
{
var block = new Block { Kind = kind, Declaration = decl };
PushBlock(block);
}
/// <summary>
/// Represents a (nestable) block of text with a specific kind.
/// </summary>
public interface IBlock<TBlock, TKind>
public void PushBlock(Block block)
{
TKind Kind { get; set; }
List<TBlock> Blocks { get; set; }
TBlock Parent { get; set; }
block.Parent = ActiveBlock;
ActiveBlock.AddBlock(block);
ActiveBlock = block;
}
TextGenerator Text { get; set; }
Declaration Declaration { get; set; }
public void PopBlock(NewLineKind newLineKind = NewLineKind.Never)
{
ActiveBlock.NewLineKind = newLineKind;
ActiveBlock = ActiveBlock.Parent;
}
/// <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 IEnumerable<Block> FindBlocks(int kind)
{
public struct BlockData
return RootBlock.FindBlocks(kind);
}
public Block FindBlock(int kind)
{
public TBlock Block;
public int StartPosition;
return FindBlocks(kind).Single();
}
public List<TBlock> Blocks { get; private set; }
protected readonly Stack<BlockData> CurrentBlocks;
#endregion
#region ITextGenerator implementation
protected BlockGenerator(Driver driver, TranslationUnit unit)
: base(driver, unit)
public uint Indent { get { return ActiveBlock.Indent; } }
public void Write(string msg, params object[] args)
{
Blocks = new List<TBlock>();
CurrentBlocks = new Stack<BlockData>();
ActiveBlock.Write(msg, args);
}
public void PushBlock(TKind kind)
{
var data = new BlockData
public void WriteLine(string msg, params object[] args)
{
Block = new TBlock { Kind = kind },
StartPosition = StringBuilder.Length
};
CurrentBlocks.Push(data);
ActiveBlock.WriteLine(msg, args);
}
public void PopBlock()
public void WriteLineIndent(string msg, params object[] args)
{
var data = CurrentBlocks.Pop();
var block = data.Block;
ActiveBlock.WriteLineIndent(msg, args);
}
var text = StringBuilder.ToString().Substring(data.StartPosition);
block.Text = Clone();
block.Text.StringBuilder = new StringBuilder(text);
public void NewLine()
{
ActiveBlock.NewLine();
}
var hasParentBlock = CurrentBlocks.Count > 0;
if (hasParentBlock)
CurrentBlocks.Peek().Block.Blocks.Add(block);
else
Blocks.Add(block);
public void NewLineIfNeeded()
{
ActiveBlock.NewLineIfNeeded();
}
public TBlock FindBlock(TKind kind)
public void NeedNewLine()
{
//foreach (var block in Blocks)
// if (block.Kind == kind)
// return block;
return default(TBlock);
ActiveBlock.NeedNewLine();
}
public override string GenerateText()
public void ResetNewLine()
{
var generator = new TextGenerator();
ActiveBlock.ResetNewLine();
}
foreach (var block in Blocks)
GenerateBlock(block, generator);
public void PushIndent(uint indent = 4u)
{
ActiveBlock.PushIndent(indent);
}
return generator.ToString();
public void PopIndent()
{
ActiveBlock.PopIndent();
}
void GenerateBlock(TBlock block, TextGenerator gen)
public void WriteStartBraceIndent()
{
if (block.Blocks.Count == 0)
gen.Write(block.Text);
ActiveBlock.WriteStartBraceIndent();
}
foreach (var childBlock in block.Blocks)
GenerateBlock(childBlock, gen);
public void WriteCloseBraceIndent()
{
ActiveBlock.WriteCloseBraceIndent();
}
#endregion
}
}

25
src/Generator/Utils/TextGenerator.cs

@ -5,15 +5,36 @@ using System.Text; @@ -5,15 +5,36 @@ using System.Text;
namespace CppSharp
{
public class TextGenerator
public interface ITextGenerator
{
const uint DefaultIndent = 4;
uint Indent { get; }
void Write(string msg, params object[] args);
void WriteLine(string msg, params object[] args);
void WriteLineIndent(string msg, params object[] args);
void NewLine();
void NewLineIfNeeded();
void NeedNewLine();
void ResetNewLine();
void PushIndent(uint indent = TextGenerator.DefaultIndent);
void PopIndent();
void WriteStartBraceIndent();
void WriteCloseBraceIndent();
}
public class TextGenerator : ITextGenerator
{
public const uint DefaultIndent = 4;
public StringBuilder StringBuilder;
protected bool IsStartOfLine;
protected bool NeedsNewLine;
protected readonly Stack<uint> CurrentIndent;
public uint Indent
{
get { return (uint)CurrentIndent.Sum(u => (int)u); }
}
public TextGenerator()
{
StringBuilder = new StringBuilder();

Loading…
Cancel
Save