Tools and libraries to glue C/C++ APIs to high-level languages
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

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
}
}