mirror of https://github.com/mono/CppSharp.git
c-sharpdotnetmonobindingsbridgecclangcpluspluscppsharpglueinteropparserparsingpinvokeswigsyntax-treevisitorsxamarinxamarin-bindings
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
402 lines
9.7 KiB
402 lines
9.7 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Diagnostics; |
|
using System.Linq; |
|
using System.Text; |
|
|
|
namespace CppSharp |
|
{ |
|
public enum NewLineKind |
|
{ |
|
Never, |
|
Always, |
|
BeforeNextBlock, |
|
IfNotEmpty |
|
} |
|
|
|
public enum BlockKind |
|
{ |
|
Unknown, |
|
Block, |
|
BlockComment, |
|
InlineComment, |
|
Header, |
|
Footer, |
|
Usings, |
|
Namespace, |
|
TranslationUnit, |
|
Enum, |
|
EnumItem, |
|
Typedef, |
|
Class, |
|
InternalsClass, |
|
InternalsClassMethod, |
|
InternalsClassField, |
|
Functions, |
|
Function, |
|
Method, |
|
Event, |
|
Variable, |
|
Property, |
|
Field, |
|
VTableDelegate, |
|
Region, |
|
Interface, |
|
Finalizer, |
|
Includes, |
|
IncludesForwardReferences, |
|
ForwardReferences, |
|
MethodBody, |
|
FunctionsClass, |
|
Template, |
|
Destructor, |
|
AccessSpecifier, |
|
Fields, |
|
Constructor, |
|
ConstructorBody, |
|
DestructorBody, |
|
FinalizerBody |
|
} |
|
|
|
[DebuggerDisplay("{Kind} | {Object}")] |
|
public class Block : ITextGenerator |
|
{ |
|
public TextGenerator Text { get; set; } |
|
public BlockKind Kind { get; set; } |
|
public NewLineKind NewLineKind { get; set; } |
|
|
|
public object Object { get; set; } |
|
|
|
public Block Parent { get; set; } |
|
public List<Block> Blocks { get; set; } |
|
|
|
private bool hasIndentChanged; |
|
|
|
public Func<bool> CheckGenerate; |
|
|
|
public Block() : this(BlockKind.Unknown) |
|
{ |
|
|
|
} |
|
|
|
public Block(BlockKind kind) |
|
{ |
|
Kind = kind; |
|
Blocks = new List<Block>(); |
|
Text = new TextGenerator(); |
|
hasIndentChanged = false; |
|
} |
|
|
|
public void AddBlock(Block block) |
|
{ |
|
if (Text.StringBuilder.Length != 0 || hasIndentChanged) |
|
{ |
|
hasIndentChanged = false; |
|
var newBlock = new Block { Text = Text.Clone() }; |
|
Text.StringBuilder.Clear(); |
|
|
|
AddBlock(newBlock); |
|
} |
|
|
|
block.Parent = this; |
|
Blocks.Add(block); |
|
} |
|
|
|
public IEnumerable<Block> FindBlocks(BlockKind 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 StringBuilder Generate() |
|
{ |
|
if (CheckGenerate != null && !CheckGenerate()) |
|
return new StringBuilder(); |
|
|
|
if (Blocks.Count == 0) |
|
return Text.StringBuilder; |
|
|
|
var builder = new StringBuilder(); |
|
Block previousBlock = null; |
|
var previousBlockEmpty = false; |
|
|
|
foreach (var childBlock in Blocks) |
|
{ |
|
var childText = childBlock.Generate(); |
|
if (childText.Length == 0) |
|
continue; |
|
|
|
if (previousBlock != null && |
|
(previousBlock.NewLineKind == NewLineKind.BeforeNextBlock || |
|
(previousBlock.NewLineKind == NewLineKind.IfNotEmpty && !previousBlockEmpty))) |
|
builder.AppendLine(); |
|
|
|
builder.Append(childText); |
|
|
|
if (childBlock.NewLineKind == NewLineKind.Always) |
|
builder.AppendLine(); |
|
|
|
previousBlock = childBlock; |
|
previousBlockEmpty = childText.Length == 0; |
|
} |
|
|
|
if (Text.StringBuilder.Length != 0) |
|
builder.Append(Text.StringBuilder); |
|
|
|
return builder; |
|
} |
|
|
|
public bool IsEmpty |
|
{ |
|
get |
|
{ |
|
return Blocks.All(block => block.IsEmpty) && string.IsNullOrEmpty(Text.ToString()); |
|
} |
|
} |
|
|
|
#region ITextGenerator implementation |
|
|
|
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 bool NeedsNewLine |
|
{ |
|
get => Text.NeedsNewLine; |
|
set => Text.NeedsNewLine = value; |
|
} |
|
|
|
public void ResetNewLine() |
|
{ |
|
Text.ResetNewLine(); |
|
} |
|
|
|
public void Indent(uint indentation = 4u) |
|
{ |
|
hasIndentChanged = true; |
|
Text.Indent(indentation); |
|
} |
|
|
|
public void Unindent() |
|
{ |
|
hasIndentChanged = true; |
|
Text.Unindent(); |
|
} |
|
|
|
public void WriteOpenBraceAndIndent() |
|
{ |
|
Text.WriteOpenBraceAndIndent(); |
|
} |
|
|
|
public void UnindentAndWriteCloseBrace() |
|
{ |
|
Text.UnindentAndWriteCloseBrace(); |
|
} |
|
|
|
#endregion |
|
} |
|
|
|
public abstract class BlockGenerator : ITextGenerator |
|
{ |
|
private static string[] LineBreakSequences = new[] { "\r\n", "\r", "\n" }; |
|
|
|
public Block RootBlock { get; } |
|
public Block ActiveBlock { get; private set; } |
|
public uint CurrentIndentation => ActiveBlock.Text.CurrentIndentation; |
|
|
|
protected BlockGenerator() |
|
{ |
|
RootBlock = new Block(); |
|
ActiveBlock = RootBlock; |
|
} |
|
|
|
public virtual string Generate() |
|
{ |
|
return RootBlock.Generate().ToString(); |
|
} |
|
|
|
#region Block helpers |
|
|
|
public void AddBlock(Block block) |
|
{ |
|
ActiveBlock.AddBlock(block); |
|
} |
|
|
|
public void PushBlock(BlockKind kind = BlockKind.Unknown, object obj = null) |
|
{ |
|
var block = new Block |
|
{ |
|
Kind = kind, |
|
Object = obj, |
|
Text = |
|
{ |
|
CurrentIndentation = CurrentIndentation, |
|
IsStartOfLine = ActiveBlock.Text.IsStartOfLine, |
|
NeedsNewLine = ActiveBlock.Text.NeedsNewLine |
|
} |
|
}; |
|
|
|
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<Block> FindBlocks(BlockKind kind) |
|
{ |
|
return RootBlock.FindBlocks(kind); |
|
} |
|
|
|
public Block FindBlock(BlockKind kind) |
|
{ |
|
return FindBlocks(kind).SingleOrDefault(); |
|
} |
|
|
|
#endregion |
|
|
|
#region ITextGenerator implementation |
|
|
|
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 WriteLines(string msg, bool trimIndentation = false) |
|
{ |
|
var lines = msg.Split(LineBreakSequences, StringSplitOptions.None); |
|
int indentation = int.MaxValue; |
|
|
|
if (trimIndentation) |
|
{ |
|
foreach (var line in lines) |
|
{ |
|
for (int i = 0; i < line.Length; ++i) |
|
{ |
|
if (char.IsWhiteSpace(line[i])) |
|
continue; |
|
|
|
if (i < indentation) |
|
{ |
|
indentation = i; |
|
break; |
|
} |
|
} |
|
} |
|
} |
|
|
|
bool foundNonEmptyLine = false; |
|
foreach (var line in lines) |
|
{ |
|
if (!foundNonEmptyLine && string.IsNullOrEmpty(line)) |
|
continue; |
|
|
|
WriteLine(line.Length >= indentation ? line.Substring(indentation) : line); |
|
foundNonEmptyLine = true; |
|
} |
|
} |
|
|
|
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 bool NeedsNewLine |
|
{ |
|
get => ActiveBlock.NeedsNewLine; |
|
set => ActiveBlock.NeedsNewLine = value; |
|
} |
|
|
|
public void ResetNewLine() |
|
{ |
|
ActiveBlock.ResetNewLine(); |
|
} |
|
|
|
public void Indent(uint indentation = 4u) |
|
{ |
|
ActiveBlock.Indent(indentation); |
|
} |
|
|
|
public void Unindent() |
|
{ |
|
ActiveBlock.Unindent(); |
|
} |
|
|
|
public void WriteOpenBraceAndIndent() |
|
{ |
|
ActiveBlock.WriteOpenBraceAndIndent(); |
|
} |
|
|
|
public void UnindentAndWriteCloseBrace() |
|
{ |
|
ActiveBlock.UnindentAndWriteCloseBrace(); |
|
} |
|
|
|
#endregion |
|
} |
|
}
|
|
|