From 7a5c34e0bce13efa36570871ee863645a0a304ff Mon Sep 17 00:00:00 2001 From: Joao Matos Date: Tue, 31 Jan 2017 20:09:29 +0000 Subject: [PATCH] Refactor the block-based text generator into own class. --- src/Generator/Generators/Template.cs | 390 +------------------ src/Generator/Passes/ObjectOverridesPass.cs | 2 +- src/Generator/Utils/BlockGenerator.cs | 404 ++++++++++++++++++++ 3 files changed, 409 insertions(+), 387 deletions(-) create mode 100644 src/Generator/Utils/BlockGenerator.cs diff --git a/src/Generator/Generators/Template.cs b/src/Generator/Generators/Template.cs index d771855e..5d85e1fb 100644 --- a/src/Generator/Generators/Template.cs +++ b/src/Generator/Generators/Template.cs @@ -1,284 +1,9 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using CppSharp.AST; namespace CppSharp.Generators { - public enum NewLineKind - { - Never, - Always, - BeforeNextBlock, - IfNotEmpty - } - - 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; } - public List Blocks { get; set; } - - public Declaration Declaration { get; set; } - - private bool hasIndentChanged; - private bool isSubBlock; - - public Func CheckGenerate; - - public Block() : this(BlockKind.Unknown) - { - - } - - public Block(int kind) - { - Kind = kind; - Blocks = new List(); - 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 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 (CheckGenerate != null && !CheckGenerate()) - return ""; - - if (Blocks.Count == 0) - return Text.ToString(); - - var builder = new StringBuilder(); - uint totalIndent = 0; - Block previousBlock = null; - - var blockIndex = 0; - foreach (var childBlock in Blocks) - { - var childText = childBlock.Generate(options); - - var nextBlock = (++blockIndex < Blocks.Count) - ? Blocks[blockIndex] - : null; - - var skipBlock = false; - if (nextBlock != null) - { - var nextText = nextBlock.Generate(options); - if (string.IsNullOrEmpty(nextText) && - childBlock.NewLineKind == NewLineKind.IfNotEmpty) - skipBlock = true; - } - - if (skipBlock) - continue; - - 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; - - 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, StringComparison.Ordinal)) - 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(); - } - - public StringBuilder GenerateUnformatted(DriverOptions options) - { - if (CheckGenerate != null && !CheckGenerate()) - return new StringBuilder(0); - - if (Blocks.Count == 0) - return Text.StringBuilder; - - var builder = new StringBuilder(); - Block previousBlock = null; - - var blockIndex = 0; - foreach (var childBlock in Blocks) - { - var childText = childBlock.GenerateUnformatted(options); - - var nextBlock = (++blockIndex < Blocks.Count) - ? Blocks[blockIndex] - : null; - - if (nextBlock != null) - { - var nextText = nextBlock.GenerateUnformatted(options); - if (nextText.Length == 0 && - childBlock.NewLineKind == NewLineKind.IfNotEmpty) - continue; - } - - if (childText.Length == 0) - continue; - - if (previousBlock != null && - previousBlock.NewLineKind == NewLineKind.BeforeNextBlock) - builder.AppendLine(); - - builder.Append(childText); - - if (childBlock.NewLineKind == NewLineKind.Always) - builder.AppendLine(); - - previousBlock = childBlock; - } - - if (Text.StringBuilder.Length != 0) - builder.Append(Text.StringBuilder); - - return builder; - } - - public bool IsEmpty - { - get - { - if (Blocks.Any(block => !block.IsEmpty)) - return false; - - return string.IsNullOrEmpty(Text.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 abstract class Template : BlockGenerator { public BindingContext Context { get; private set; } @@ -289,129 +14,22 @@ namespace CppSharp.Generators public TranslationUnit TranslationUnit { get { return TranslationUnits[0]; } } - public Block RootBlock { get; private set; } - public Block ActiveBlock { get; private set; } - public abstract string FileExtension { get; } protected Template(BindingContext context, IEnumerable units) { Context = context; TranslationUnits = new List(units); - RootBlock = new Block(); - ActiveBlock = RootBlock; } public abstract void Process(); - public string Generate() + public new string Generate() { if (Options.IsCSharpGenerator && Options.CompileCode) - return RootBlock.GenerateUnformatted(Options).ToString(); - return RootBlock.Generate(Options); - } - - #region Block helpers - - public void AddBlock(Block block) - { - ActiveBlock.AddBlock(block); - } - - public void PushBlock(int kind, Declaration decl = null) - { - var block = new Block { Kind = kind, Declaration = decl }; - PushBlock(block); - } - - public void PushBlock(Block block) - { - block.Parent = ActiveBlock; - ActiveBlock.AddBlock(block); - ActiveBlock = block; - } - - public Block PopBlock(NewLineKind newLineKind = NewLineKind.Never) - { - var block = ActiveBlock; - - ActiveBlock.NewLineKind = newLineKind; - ActiveBlock = ActiveBlock.Parent; - - return block; - } + return base.GenerateUnformatted(); - public IEnumerable FindBlocks(int kind) - { - return RootBlock.FindBlocks(kind); - } - - public Block FindBlock(int kind) - { - return FindBlocks(kind).SingleOrDefault(); + return base.Generate(); } - - #endregion - - #region ITextGenerator implementation - - public uint Indent { get { return ActiveBlock.Indent; } } - - public void Write(string msg, params object[] args) - { - ActiveBlock.Write(msg, args); - } - - public void WriteLine(string msg, params object[] args) - { - ActiveBlock.WriteLine(msg, args); - } - - public void WriteLineIndent(string msg, params object[] args) - { - ActiveBlock.WriteLineIndent(msg, args); - } - - public void NewLine() - { - ActiveBlock.NewLine(); - } - - public void NewLineIfNeeded() - { - ActiveBlock.NewLineIfNeeded(); - } - - public void NeedNewLine() - { - ActiveBlock.NeedNewLine(); - } - - public void ResetNewLine() - { - ActiveBlock.ResetNewLine(); - } - - public void PushIndent(uint indent = 4u) - { - ActiveBlock.PushIndent(indent); - } - - public void PopIndent() - { - ActiveBlock.PopIndent(); - } - - public void WriteStartBraceIndent() - { - ActiveBlock.WriteStartBraceIndent(); - } - - public void WriteCloseBraceIndent() - { - ActiveBlock.WriteCloseBraceIndent(); - } - - #endregion } } diff --git a/src/Generator/Passes/ObjectOverridesPass.cs b/src/Generator/Passes/ObjectOverridesPass.cs index 8d3f1171..19b49c8e 100644 --- a/src/Generator/Passes/ObjectOverridesPass.cs +++ b/src/Generator/Passes/ObjectOverridesPass.cs @@ -30,7 +30,7 @@ namespace CppSharp { foreach (var block in template.FindBlocks(CLIBlockKind.MethodBody)) { - var method = block.Declaration as Method; + var method = block.Object as Method; VisitMethod(method, block); } if (needsStreamInclude) diff --git a/src/Generator/Utils/BlockGenerator.cs b/src/Generator/Utils/BlockGenerator.cs new file mode 100644 index 00000000..1370a70a --- /dev/null +++ b/src/Generator/Utils/BlockGenerator.cs @@ -0,0 +1,404 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace CppSharp +{ + public enum NewLineKind + { + Never, + Always, + BeforeNextBlock, + IfNotEmpty + } + + 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 object Object { get; set; } + + public Block Parent { get; set; } + public List Blocks { get; set; } + + private bool hasIndentChanged; + private bool isSubBlock; + + public Func CheckGenerate; + + public Block() : this(BlockKind.Unknown) + { + + } + + public Block(int kind) + { + Kind = kind; + Blocks = new List(); + 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 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() + { + if (CheckGenerate != null && !CheckGenerate()) + return ""; + + if (Blocks.Count == 0) + return Text.ToString(); + + var builder = new StringBuilder(); + uint totalIndent = 0; + Block previousBlock = null; + + var blockIndex = 0; + foreach (var childBlock in Blocks) + { + var childText = childBlock.Generate(); + + var nextBlock = (++blockIndex < Blocks.Count) + ? Blocks[blockIndex] + : null; + + var skipBlock = false; + if (nextBlock != null) + { + var nextText = nextBlock.Generate(); + if (string.IsNullOrEmpty(nextText) && + childBlock.NewLineKind == NewLineKind.IfNotEmpty) + skipBlock = true; + } + + if (skipBlock) + continue; + + 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; + + 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, StringComparison.Ordinal)) + 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(); + } + + public StringBuilder GenerateUnformatted() + { + if (CheckGenerate != null && !CheckGenerate()) + return new StringBuilder(0); + + if (Blocks.Count == 0) + return Text.StringBuilder; + + var builder = new StringBuilder(); + Block previousBlock = null; + + var blockIndex = 0; + foreach (var childBlock in Blocks) + { + var childText = childBlock.GenerateUnformatted(); + + var nextBlock = (++blockIndex < Blocks.Count) + ? Blocks[blockIndex] + : null; + + if (nextBlock != null) + { + var nextText = nextBlock.GenerateUnformatted(); + if (nextText.Length == 0 && + childBlock.NewLineKind == NewLineKind.IfNotEmpty) + continue; + } + + if (childText.Length == 0) + continue; + + if (previousBlock != null && + previousBlock.NewLineKind == NewLineKind.BeforeNextBlock) + builder.AppendLine(); + + builder.Append(childText); + + if (childBlock.NewLineKind == NewLineKind.Always) + builder.AppendLine(); + + previousBlock = childBlock; + } + + if (Text.StringBuilder.Length != 0) + builder.Append(Text.StringBuilder); + + return builder; + } + + public bool IsEmpty + { + get + { + if (Blocks.Any(block => !block.IsEmpty)) + return false; + + return string.IsNullOrEmpty(Text.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 BlockGenerator : ITextGenerator + { + public Block RootBlock { get; private set; } + public Block ActiveBlock { get; private set; } + + protected BlockGenerator() + { + RootBlock = new Block(); + ActiveBlock = RootBlock; + } + + public string Generate() + { + return RootBlock.Generate(); + } + + public string GenerateUnformatted() + { + return RootBlock.GenerateUnformatted().ToString(); + } + + #region Block helpers + + public void AddBlock(Block block) + { + ActiveBlock.AddBlock(block); + } + + public void PushBlock(int kind = 0, object obj = null) + { + var block = new Block { Kind = kind, Object = obj }; + PushBlock(block); + } + + public void PushBlock(Block block) + { + block.Parent = ActiveBlock; + ActiveBlock.AddBlock(block); + ActiveBlock = block; + } + + public Block PopBlock(NewLineKind newLineKind = NewLineKind.Never) + { + var block = ActiveBlock; + + ActiveBlock.NewLineKind = newLineKind; + ActiveBlock = ActiveBlock.Parent; + + return block; + } + + public IEnumerable FindBlocks(int kind) + { + return RootBlock.FindBlocks(kind); + } + + public Block FindBlock(int kind) + { + return FindBlocks(kind).SingleOrDefault(); + } + + #endregion + + #region ITextGenerator implementation + + public uint Indent { get { return ActiveBlock.Indent; } } + + public void Write(string msg, params object[] args) + { + ActiveBlock.Write(msg, args); + } + + public void WriteLine(string msg, params object[] args) + { + ActiveBlock.WriteLine(msg, args); + } + + public void WriteLineIndent(string msg, params object[] args) + { + ActiveBlock.WriteLineIndent(msg, args); + } + + public void NewLine() + { + ActiveBlock.NewLine(); + } + + public void NewLineIfNeeded() + { + ActiveBlock.NewLineIfNeeded(); + } + + public void NeedNewLine() + { + ActiveBlock.NeedNewLine(); + } + + public void ResetNewLine() + { + ActiveBlock.ResetNewLine(); + } + + public void PushIndent(uint indent = 4u) + { + ActiveBlock.PushIndent(indent); + } + + public void PopIndent() + { + ActiveBlock.PopIndent(); + } + + public void WriteStartBraceIndent() + { + ActiveBlock.WriteStartBraceIndent(); + } + + public void WriteCloseBraceIndent() + { + ActiveBlock.WriteCloseBraceIndent(); + } + + #endregion + } +}