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.
340 lines
8.5 KiB
340 lines
8.5 KiB
using System; |
|
using System.Collections.Generic; |
|
using System.Linq; |
|
using System.Text; |
|
using CppSharp.AST; |
|
|
|
namespace CppSharp.Generators |
|
{ |
|
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 TranslationUnit TranslationUnit { get; private set; } |
|
|
|
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; |
|
TranslationUnit = unit; |
|
RootBlock = new Block(); |
|
ActiveBlock = RootBlock; |
|
} |
|
|
|
public abstract void Process(); |
|
|
|
public string Generate() |
|
{ |
|
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 void PopBlock(NewLineKind newLineKind = NewLineKind.Never) |
|
{ |
|
ActiveBlock.NewLineKind = newLineKind; |
|
ActiveBlock = ActiveBlock.Parent; |
|
} |
|
|
|
public IEnumerable<Block> FindBlocks(int kind) |
|
{ |
|
return RootBlock.FindBlocks(kind); |
|
} |
|
|
|
public Block FindBlock(int kind) |
|
{ |
|
return FindBlocks(kind).Single(); |
|
} |
|
|
|
#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 |
|
} |
|
}
|
|
|